Hello community,
I presented until now in the series "How to use actual SAPNetWeaver RFC Library with Pyhton" :
Here now an example how to use Python as server application from ABAP.
We start with the transaction code SM59 to configure the RFC destination of the Python server application.
Here the Python source:
# -*- coding: iso-8859-15 -*-
#-Begin-----------------------------------------------------------------
#-Packages--------------------------------------------------------------
from threading import Thread
import time
#-Include---------------------------------------------------------------
FileName = "sapnwrfc.py"
exec(compile(open(FileName).read(), FileName, "exec"))
#-Asynchronous function-------------------------------------------------
def SetQuit():
global Quit
windll.user32.MessageBoxW(None, "Stop Python server", "", 0)
Quit = True
#-ABAP CallBack---------------------------------------------------------
def ABAPCall(rfcHandle, funcHandle, RfcErrInf):
windll.user32.MessageBoxW(None, "ABAP calling", "", 0)
return RFC_OK
#-Main------------------------------------------------------------------
Quit = False
t = Thread(target=SetQuit); t.start()
#-Connection parameters-------------------------------------------------
RfcSConParams[0].name = "PROGRAM_ID"; RfcSConParams[0].value = "PYTHONSERVER"
RfcSConParams[1].name = "GWHOST" ; RfcSConParams[1].value = "ABAP"
RfcSConParams[2].name = "GWSERV" ; RfcSConParams[2].value = "sapgw00"
ABAPFunc = WINFUNCTYPE(c_ulong, c_void_p, c_void_p, POINTER(ErrInf))
hDesc = SAP.RfcCreateFunctionDesc("ABAPCall", RfcErrInf)
if hDesc != None:
if SAP.RfcInstallServerFunction("NSP", hDesc, ABAPFunc(ABAPCall), \
RfcErrInf) == RFC_OK:
hCon = SAP.RfcRegisterServer(RfcSConParams, 3, RfcErrInf)
if hCon != None:
rc = RFC_OK
while (rc == RFC_OK, rc == RFC_RETRY):
rc = SAP.RfcListenAndDispatch(hCon, 1, RfcErrInf)
time.sleep(0.250)
if Quit == True:
break
else:
print(RfcErrInf.key); print(RfcErrInf.message)
else:
print(RfcErrInf.key); print(RfcErrInf.message)
rc = SAP.RfcDestroyFunctionDesc(hDesc, RfcErrInf)
else:
print(RfcErrInf.key); print(RfcErrInf.message)
del SAP
#-End-------------------------------------------------------------------
We define at first an asynchonous thread, to set a global variable to break the execution of the server, when we no longer need it. Then we define the callback function, which can be called from ABAP - in our case only a simple message box. We create an empty function description with RfcCreateFunctionDesc and install, with this description, the callback function on the SAP system with RfcInstallServerFunction. Now we register the server connection at an SAP gateway via RFCRegisterServer and listen for incoming RFC calls with RfcListenAndDispatch. Very simple, isn't it?
Now we can use the Python function ABAPCall from ABAP like this:
"-Begin-----------------------------------------------------------------
Program ZTEST.
Call Function 'ABAPCall' Destination 'PYTHONSERVER'.
"-End-------------------------------------------------------------------
And this is the result:
As you can see, it is very easy to use Python as SAP server application.
Cheers
Stefan
P.S. Here the updated include file sapnwrfc.py:
#-Begin-----------------------------------------------------------------
#-Packages--------------------------------------------------------------
from ctypes import *
import platform, os
#-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_RC - RFC return codes---------------------------------------------
RFC_OK = 0
RFC_COMMUNICATION_FAILURE = 1
RFC_LOGON_FAILURE = 2
RFC_ABAP_RUNTIME_FAILURE = 3
RFC_ABAP_MESSAGE = 4
RFC_ABAP_EXCEPTION = 5
RFC_CLOSED = 6
RFC_CANCELED = 7
RFC_TIMEOUT = 8
RFC_MEMORY_INSUFFICIENT = 9
RFC_VERSION_MISMATCH = 10
RFC_INVALID_PROTOCOL = 11
RFC_SERIALIZATION_FAILURE = 12
RFC_INVALID_HANDLE = 13
RFC_RETRY = 14
RFC_EXTERNAL_FAILURE = 15
RFC_EXECUTED = 16
RFC_NOT_FOUND = 17
RFC_NOT_SUPPORTED = 18
RFC_ILLEGAL_STATE = 19
RFC_INVALID_PARAMETER = 20
RFC_CODEPAGE_CONVERSION_FAILURE = 21
RFC_CONVERSION_FAILURE = 22
RFC_BUFFER_TOO_SMALL = 23
RFC_TABLE_MOVE_BOF = 24
RFC_TABLE_MOVE_EOF = 25
RFC_START_SAPGUI_FAILURE = 26
RFC_ABAP_CLASS_EXCEPTION = 27
RFC_UNKNOWN_ERROR = 28
RFC_AUTHORIZATION_FAILURE = 29
#-RFCTYPE - RFC data types----------------------------------------------
RFCTYPE_CHAR = 0
RFCTYPE_DATE = 1
RFCTYPE_BCD = 2
RFCTYPE_TIME = 3
RFCTYPE_BYTE = 4
RFCTYPE_TABLE = 5
RFCTYPE_NUM = 6
RFCTYPE_FLOAT = 7
RFCTYPE_INT = 8
RFCTYPE_INT2 = 9
RFCTYPE_INT1 = 10
RFCTYPE_NULL = 14
RFCTYPE_ABAPOBJECT = 16
RFCTYPE_STRUCTURE = 17
RFCTYPE_DECF16 = 23
RFCTYPE_DECF34 = 24
RFCTYPE_XMLDATA = 28
RFCTYPE_STRING = 29
RFCTYPE_XSTRING = 30
RFCTYPE_BOX = 31
RFCTYPE_GENERIC_BOX = 32
#-RFC_UNIT_STATE - Processing status of a background unit---------------
RFC_UNIT_NOT_FOUND = 0
RFC_UNIT_IN_PROCESS = 1
RFC_UNIT_COMMITTED = 2
RFC_UNIT_ROLLED_BACK = 3
RFC_UNIT_CONFIRMED = 4
#-RFC_CALL_TYPE - Type of an incoming function call---------------------
RFC_SYNCHRONOUS = 0
RFC_TRANSACTIONAL = 1
RFC_QUEUED = 2
RFC_BACKGROUND_UNIT = 3
#-RFC_DIRECTION - Direction of a function module parameter--------------
RFC_IMPORT = 1
RFC_EXPORT = 2
RFC_CHANGING = RFC_IMPORT + RFC_EXPORT
RFC_TABLES = 4 + RFC_CHANGING
#-RFC_CLASS_ATTRIBUTE_TYPE - Type of an ABAP object attribute-----------
RFC_CLASS_ATTRIBUTE_INSTANCE = 0
RFC_CLASS_ATTRIBUTE_CLASS = 1
RFC_CLASS_ATTRIBUTE_CONSTANT = 2
#-RFC_METADATA_OBJ_TYPE - Ingroup repository----------------------------
RFC_METADATA_FUNCTION = 0
RFC_METADATA_TYPE = 1
RFC_METADATA_CLASS = 2
#-Variables-------------------------------------------------------------
ErrInf = RFC_ERROR_INFO; RfcErrInf = ErrInf()
ConnParams = RFC_CONNECTION_PARAMETER * 5; RfcConnParams = ConnParams()
SConParams = RFC_CONNECTION_PARAMETER * 3; RfcSConParams = SConParams()
#-Library---------------------------------------------------------------
if str(platform.architecture()[0]) == "32bit":
os.environ['PATH'] += ";C:\\SAPRFCSDK\\32bit"
SAPNWRFC = "C:\\SAPRFCSDK\\32bit\\sapnwrfc.dll"
elif str(platform.architecture()[0]) == "64bit":
os.environ['PATH'] += ";C:\\SAPRFCSDK\\64bit"
SAPNWRFC = "C:\\SAPRFCSDK\\64bit\\sapnwrfc.dll"
SAP = windll.LoadLibrary(SAPNWRFC)
#-Prototypes------------------------------------------------------------
SAP.RfcAppendNewRow.argtypes = [c_void_p, POINTER(ErrInf)]
SAP.RfcAppendNewRow.restype = c_void_p
SAP.RfcCloseConnection.argtypes = [c_void_p, POINTER(ErrInf)]
SAP.RfcCloseConnection.restype = c_ulong
SAP.RfcCreateFunction.argtypes = [c_void_p, POINTER(ErrInf)]
SAP.RfcCreateFunction.restype = c_void_p
SAP.RfcCreateFunctionDesc.argtypes = [c_wchar_p, POINTER(ErrInf)]
SAP.RfcCreateFunctionDesc.restype = c_void_p
SAP.RfcDestroyFunction.argtypes = [c_void_p, POINTER(ErrInf)]
SAP.RfcDestroyFunction.restype = c_ulong
SAP.RfcDestroyFunctionDesc.argtypes = [c_void_p, POINTER(ErrInf)]
SAP.RfcDestroyFunctionDesc.restype = c_ulong
SAP.RfcGetChars.argtypes = [c_void_p, c_wchar_p, c_void_p, c_ulong, \
POINTER(ErrInf)]
SAP.RfcGetChars.restype = c_ulong
SAP.RfcGetCurrentRow.argtypes = [c_void_p, POINTER(ErrInf)]
SAP.RfcGetCurrentRow.restype = c_void_p
SAP.RfcGetFunctionDesc.argtypes = [c_void_p, c_wchar_p, POINTER(ErrInf)]
SAP.RfcGetFunctionDesc.restype = c_void_p
SAP.RfcGetRowCount.argtypes = [c_void_p, POINTER(c_ulong), \
POINTER(ErrInf)]
SAP.RfcGetRowCount.restype = c_ulong
SAP.RfcGetStructure.argtypes = [c_void_p, c_wchar_p, \
POINTER(c_void_p), POINTER(ErrInf)]
SAP.RfcGetStructure.restype = c_ulong
SAP.RfcGetTable.argtypes = [c_void_p, c_wchar_p, POINTER(c_void_p), \
POINTER(ErrInf)]
SAP.RfcGetTable.restype = c_ulong
SAP.RfcGetVersion.argtypes = [POINTER(c_ulong), POINTER(c_ulong), \
POINTER(c_ulong)]
SAP.RfcGetVersion.restype = c_wchar_p
SAP.RfcInstallServerFunction.argtypes = [c_wchar_p, c_void_p, \
c_void_p, POINTER(ErrInf)]
SAP.RfcInstallServerFunction.restype = c_ulong
SAP.RfcInvoke.argtypes = [c_void_p, c_void_p, POINTER(ErrInf)]
SAP.RfcInvoke.restype = c_ulong
SAP.RfcListenAndDispatch.argtypes = [c_void_p, c_ulong, POINTER(ErrInf)]
SAP.RfcListenAndDispatch.restype = c_ulong
SAP.RfcMoveToFirstRow.argtypes = [c_void_p, POINTER(ErrInf)]
SAP.RfcMoveToFirstRow.restype = c_ulong
SAP.RfcMoveToNextRow.argtypes = [c_void_p, POINTER(ErrInf)]
SAP.RfcMoveToNextRow.restype = c_ulong
SAP.RfcOpenConnection.argtypes = [POINTER(ConnParams), c_ulong, \
POINTER(ErrInf)]
SAP.RfcOpenConnection.restype = c_void_p
SAP.RfcPing.argtypes = [c_void_p, POINTER(ErrInf)]
SAP.RfcPing.restype = c_ulong
SAP.RfcRegisterServer.argtypes = [POINTER(SConParams), c_ulong, \
POINTER(ErrInf)]
SAP.RfcRegisterServer.restype = c_void_p
SAP.RfcSetChars.argtypes = [c_void_p, c_wchar_p, c_wchar_p, c_ulong, \
POINTER(ErrInf)]
SAP.RfcSetChars.restype = c_ulong
#-End-------------------------------------------------------------------