Application Development Blog Posts
Learn and share on deeper, cross technology development topics such as integration and connectivity, automation, cloud extensibility, developing at scale, and security.
cancel
Showing results for 
Search instead for 
Did you mean: 
stefan_schnell
Active Contributor
Yesterday I presented here the first steps how to connect an SAP system via Python 3 without any additional packages. Here now the next steps, how to invoke functions. You will see how easy it is now, after the first step of connection - it is not more than a prolongation.

We start with an ordinary ping in two variants. The first variant explains how to invoke a RFC function, in our case RFC_PING. The second variant shows how to use the RfcPing function of the RFC library. In the focus of this example is the invocation of the RFC function call.

To invoke a RFC function you must get at first the description of the function via RfcGetFunctionDesc. The next step is to create the function with RfcCreateFunction and now you can invoke it. Last but not least you must destroy the created function via RfcDestroyFunction. Look at the example below.
#-Begin-----------------------------------------------------------------

#-Packages--------------------------------------------------------------
from ctypes import *

#-Structures------------------------------------------------------------
class RFC_ERROR_INFO(Structure):
_fields_ = [("code", c_long),
("group", c_long),
("key", c_wchar * 128),
("message", c_wchar * 512),
("abapMsgClass", c_wchar * 21),
("abapMsgType", c_wchar * 2),
("abapMsgNumber", c_wchar * 4),
("abapMsgV1", c_wchar * 51),
("abapMsgV2", c_wchar * 51),
("abapMsgV3", c_wchar * 51),
("abapMsgV4", c_wchar * 51)]

class RFC_CONNECTION_PARAMETER(Structure):
_fields_ = [("name", c_wchar_p),
("value", c_wchar_p)]

#-Constants-------------------------------------------------------------
RFC_OK = 0

#-Main------------------------------------------------------------------
ErrInf = RFC_ERROR_INFO; RfcErrInf = ErrInf()
ConnParams = RFC_CONNECTION_PARAMETER * 5; RfcConnParams = ConnParams()

SAPNWRFC = "sapnwrfc.dll"
SAP = windll.LoadLibrary(SAPNWRFC)

#-Prototypes------------------------------------------------------------
SAP.RfcOpenConnection.argtypes = [POINTER(ConnParams), c_ulong, \
POINTER(ErrInf)]
SAP.RfcOpenConnection.restype = c_void_p

SAP.RfcCloseConnection.argtypes = [c_void_p, POINTER(ErrInf)]
SAP.RfcCloseConnection.restype = c_ulong

SAP.RfcGetFunctionDesc.argtypes = [c_void_p, c_wchar_p, POINTER(ErrInf)]
SAP.RfcGetFunctionDesc.restype = c_void_p

SAP.RfcCreateFunction.argtypes = [c_void_p, POINTER(ErrInf)]
SAP.RfcCreateFunction.restype = c_void_p

SAP.RfcInvoke.argtypes = [c_void_p, c_void_p, POINTER(ErrInf)]
SAP.RfcInvoke.restype = c_ulong

SAP.RfcDestroyFunction.argtypes = [c_void_p, POINTER(ErrInf)]
SAP.RfcDestroyFunction.restype = c_ulong

SAP.RfcPing.argtypes = [c_void_p, POINTER(ErrInf)]
SAP.RfcPing.restype = c_ulong

#-Connection parameters-------------------------------------------------
RfcConnParams[0].name = "ASHOST"; RfcConnParams[0].value = "ABAP"
RfcConnParams[1].name = "SYSNR" ; RfcConnParams[1].value = "00"
RfcConnParams[2].name = "CLIENT"; RfcConnParams[2].value = "001"
RfcConnParams[3].name = "USER" ; RfcConnParams[3].value = "BCUSER"
RfcConnParams[4].name = "PASSWD"; RfcConnParams[4].value = "minisap"

hRFC = SAP.RfcOpenConnection(RfcConnParams, 5, RfcErrInf)
if hRFC != None:

#-Variant 1-----------------------------------------------------------
hFuncDesc = SAP.RfcGetFunctionDesc(hRFC, "RFC_PING", RfcErrInf)
if hFuncDesc != 0:
hFunc = SAP.RfcCreateFunction(hFuncDesc, RfcErrInf)
if hFunc != 0:
if SAP.RfcInvoke(hRFC, hFunc, RfcErrInf) == RFC_OK:
print("Ping successful")
else:
print("Ping not successful")
rc = SAP.RfcDestroyFunction(hFunc, RfcErrInf)

#-Variant 2-----------------------------------------------------------
if SAP.RfcPing(hRFC, RfcErrInf) == RFC_OK:
print("Ping successful")
else:
print("Ping not successful")

rc = SAP.RfcCloseConnection(hRFC, RfcErrInf)

else:
print(RfcErrInf.key)
print(RfcErrInf.message)

del SAP

#-End-------------------------------------------------------------------

 

In the next example I demonstrate how to invoke the function RFC_SYSTEM_INFO. It is the same way as I described above, until the invocation of the function. After the invocation we get the information of the function module via RfcGetStructure and RfcGetChars, in our case SYSID, HOST, DBHOST and DBSYS - that's all. Look at the example below:
#-Begin-----------------------------------------------------------------

#-Packages--------------------------------------------------------------
from ctypes import *

#-Structures------------------------------------------------------------
class RFC_ERROR_INFO(Structure):
_fields_ = [("code", c_long),
("group", c_long),
("key", c_wchar * 128),
("message", c_wchar * 512),
("abapMsgClass", c_wchar * 21),
("abapMsgType", c_wchar * 2),
("abapMsgNumber", c_wchar * 4),
("abapMsgV1", c_wchar * 51),
("abapMsgV2", c_wchar * 51),
("abapMsgV3", c_wchar * 51),
("abapMsgV4", c_wchar * 51)]

class RFC_CONNECTION_PARAMETER(Structure):
_fields_ = [("name", c_wchar_p),
("value", c_wchar_p)]

#-Constants-------------------------------------------------------------
RFC_OK = 0

#-Main------------------------------------------------------------------
ErrInf = RFC_ERROR_INFO; RfcErrInf = ErrInf()
ConnParams = RFC_CONNECTION_PARAMETER * 5; RfcConnParams = ConnParams()

SAPNWRFC = "sapnwrfc.dll"
SAP = windll.LoadLibrary(SAPNWRFC)

#-Prototypes------------------------------------------------------------
SAP.RfcOpenConnection.argtypes = [POINTER(ConnParams), c_ulong, \
POINTER(ErrInf)]
SAP.RfcOpenConnection.restype = c_void_p

SAP.RfcCloseConnection.argtypes = [c_void_p, POINTER(ErrInf)]
SAP.RfcCloseConnection.restype = c_ulong

SAP.RfcGetFunctionDesc.argtypes = [c_void_p, c_wchar_p, POINTER(ErrInf)]
SAP.RfcGetFunctionDesc.restype = c_void_p

SAP.RfcCreateFunction.argtypes = [c_void_p, POINTER(ErrInf)]
SAP.RfcCreateFunction.restype = c_void_p

SAP.RfcInvoke.argtypes = [c_void_p, c_void_p, POINTER(ErrInf)]
SAP.RfcInvoke.restype = c_ulong

SAP.RfcDestroyFunction.argtypes = [c_void_p, POINTER(ErrInf)]
SAP.RfcDestroyFunction.restype = c_ulong

SAP.RfcGetStructure.argtypes = [c_void_p, c_wchar_p, \
POINTER(c_void_p), POINTER(ErrInf)]
SAP.RfcGetStructure.restype = c_ulong

SAP.RfcGetChars.argtypes = [c_void_p, c_wchar_p, c_void_p, c_ulong, \
POINTER(ErrInf)]
SAP.RfcGetChars.restype = c_ulong

#-Connection parameters-------------------------------------------------
RfcConnParams[0].name = "ASHOST"; RfcConnParams[0].value = "ABAP"
RfcConnParams[1].name = "SYSNR" ; RfcConnParams[1].value = "00"
RfcConnParams[2].name = "CLIENT"; RfcConnParams[2].value = "001"
RfcConnParams[3].name = "USER" ; RfcConnParams[3].value = "BCUSER"
RfcConnParams[4].name = "PASSWD"; RfcConnParams[4].value = "minisap"

hRFC = SAP.RfcOpenConnection(RfcConnParams, 5, RfcErrInf)
if hRFC != None:

hFuncDesc = SAP.RfcGetFunctionDesc(hRFC, "RFC_SYSTEM_INFO", RfcErrInf)
if hFuncDesc != 0:
hFunc = SAP.RfcCreateFunction(hFuncDesc, RfcErrInf)
if hFunc != 0:
if SAP.RfcInvoke(hRFC, hFunc, RfcErrInf) == RFC_OK:
hStruct = c_void_p(0)
if SAP.RfcGetStructure(hFunc, "RFCSI_EXPORT", hStruct, \
RfcErrInf) == RFC_OK:

SAPHost = create_unicode_buffer(8 + 1)
rc = SAP.RfcGetChars(hStruct, "RFCHOST", SAPHost, 8, \
RfcErrInf)
print(SAPHost.value)

SAPSysID = create_unicode_buffer(8 + 1)
rc = SAP.RfcGetChars(hStruct, "RFCSYSID", SAPSysID, 8, \
RfcErrInf)
print(SAPSysID.value)

SAPDBHost = create_unicode_buffer(32 + 1)
rc = SAP.RfcGetChars(hStruct, "RFCDBHOST", SAPDBHost, 32, \
RfcErrInf)
print(SAPDBHost.value)

SAPDBSys = create_unicode_buffer(10 + 1)
rc = SAP.RfcGetChars(hStruct, "RFCDBSYS", SAPDBSys, 10, \
RfcErrInf)
print(SAPDBSys.value)

rc = SAP.RfcDestroyFunction(hFunc, RfcErrInf)

rc = SAP.RfcCloseConnection(hRFC, RfcErrInf)

else:
print(RfcErrInf.key)
print(RfcErrInf.message)

del SAP

#-End-------------------------------------------------------------------

 

With the COM Connector (CCo) I published a lot of examples, which can be almost identical implemented in Python. All you have to do is to define the argument and result type of the prototype of the function. As you can see it is easy to use SAP NetWeaver RFC library with Python 3. I hope this examples opens the gate wide for the future development of this kind of requirements.

2015/09/16: Three days ago the new Python release 3.5.0 has been published. The method above works perfect with the new release.

2017/04/24: I check the method above with Python release 3.6.1 x64 and with the SAP NetWeaver RFC library 721 PL42 x64 and it works perfect.
2 Comments