Skip to Content
Technical Articles
Author's profile photo Stefan Schnell

CCo (COM Connector) for SAP NetWeaver RFC Library for Scripting Languages

SAP offers different connectors to develop ABAP compatible components and applications. JCo for Java environments, NCo for dotNET languages and the NetWeaver RFC SDK for C++. But what’s up if you work neither with Java or dotNET environments nor with C++?

Here is another alternative, CCo – the COM Connector for SAP. CCo is a COM library and offers wrappers around all functions of the SAP NetWeaver RFC library. So it is possible to use all functionalities of the SAP NetWeaver RFC library inside any language which supports COM technic.

With CCo it is easily possible to use the SAP NetWeaver RFC functions inside VBScript, Visual Basic for Applications (VBA) or AutoIt script.

Here a VBScript example to connect an SAP system:

'-Begin-----------------------------------------------------------------

  '-Directives----------------------------------------------------------
    Option Explicit

  '-Variables-----------------------------------------------------------
    Dim SAP, hRFC, rc

  '-Main----------------------------------------------------------------
    Set SAP = CreateObject("COMNWRFC")

    If IsObject(SAP) Then

      SAP.About

      hRFC = SAP.RfcOpenConnection("ASHOST=ABAP, SYSNR=00, " & _
        "CLIENT=001, USER=BCUSER")

      If hRFC Then
        MsgBox "Check connection with TAC SMGW in the SAP system"
        rc = SAP.RfcCloseConnection(hRFC)
      End If

      Set SAP = Nothing

    End If

'-End-------------------------------------------------------------------

Here a VBA example to ping an SAP system:

'-Begin-----------------------------------------------------------------

  Option Explicit

  '-Constants-----------------------------------------------------------
    Const RFC_OK = 0

  '-Sub Ping------------------------------------------------------------
    Sub Ping()

      '-Variables-------------------------------------------------------
        Dim SAP As CCo.COMNWRFC
        Dim hRFC As Long
        Dim rc As Integer
        Dim hFunc, hFuncDesc As Long

      Set SAP = CreateObject("COMNWRFC")
      If IsObject(SAP) Then
        hRFC = SAP.RFCOPENCONNECTION("ASHOST=ABAP, SYSNR=00, " & _
          "CLIENT=001, USER=BCUSER")
        If hRFC Then

          '-Variant1----------------------------------------------------
            hFuncDesc = SAP.RFCGETFUNCTIONDESC(hRFC, "RFC_PING")
            If hFuncDesc Then
              hFunc = SAP.RFCCREATEFUNCTION(hFuncDesc)
              If hFunc Then
                If SAP.RFCINVOKE(hRFC, hFunc) = RFC_OK Then
                  Debug.Print "Ping successful"
                Else
                  Debug.Print "Ping not successful"
                End If
                SAP.RFCDESTROYFUNCTION hFunc
              End If
            End If

          '-Variant2----------------------------------------------------
            If SAP.RFCPING(hRFC) = RFC_OK Then
              Debug.Print "Ping successful"
            Else
              Debug.Print "Ping not successful"
            End If

          rc = SAP.RFCCLOSECONNECTION(hRFC)
        End If
        Set SAP = Nothing
      End If
    End Sub

'-End-------------------------------------------------------------------

To the duality of accesses via SAP GUI Scripting and RFC with scripting languages

ScriptStructure3.jpg

CCo opens a powerful second channel to communicate with an SAP backend. You can code in your favorite COM-enabled scripting language and use two ways: on the one hand the SAP GUI Scripting to communicate via SAP GUI for Windows with an SAP system, and on the other hand the COM Connector (CCo) to communicate via SAP NetWeaver RFC library with an SAP application server.

CCo is an ideal complementation to SAP GUI Scripting in this application area. You can e.g. use the wide range of thousands of remote-enabled function modules from an SAP system. Use the transaction code BAPI to open the BAPI explorer and find a lot in the alphabetical hierarchy tree.

Enrich your SAP GUI Scripting operation processes. Get information easy and fast via CCo RFC interface in your scripting environment. Combine the best of both worlds.

Hint: CCo needs SAP RFC SDK, you can find it here.

Download

You can find CCo here: Download is not longer available.

2018/01/01

  • Checked with actual RFC library version 7.50 patch level 0.

2016/09/09

  • New version 2.0 is available.
  • New methods GetUserPasswordDialog and GetPasswordDialog to set the corresponding fields.
  • The HTML examples, for VBScript and JavaScript, and the FBSL examples are not longer available because they have no relevance anymore.
  • The PowerShell examples are not longer available, because with PowerShell it is better to use the dotNET connector NCo.
  • The registry VBScripts are not longer available, because the Windows registry files works also.
  • New VBScript examples, e.g. to use SSO.
  • Checked with actual RFC library patch level 40.

2016/02/23

  • Actualization of the documentation and the examples

2015/12/06

  • An update is available.
  • Add the property UsePwdRequest to disable the password requester in the case of using SAPNWRFC.INI via DEST connection parameter or the using of MYSAPSSO2 connection parameter.

2015/11/20

  • New version 1.7 is available.
  • Externalization of the routine to register the library without admin rights as script, because this function doesn’t work with Windows 10.
  • Checked with Windows 10 x64.
  • Checked with actual RFC library patch level 38.

2015/01/01

  • New version 1.5 is available.
  • It includes now for arguments by reference a set of typed attributes, e.g. lngByRef for a long variable by reference. This attributes gets and sets the arguments by reference, on any method with a corresponding in and out argument.
  • So it is now possible to use CCo with JavaScript inside IE11 in edge mode, to use it in UI5 environments. New examples are included.
  • Also you can use CCo on the same way with PowerShell. New examples are included.
  • CCo is now backwards compatible, the new SAP functions since the first PL – implemented in version 1.4 – doesn’t create an error message at the creation of the instantiation.
  • Checked with actual RFC library patch level 33.

2014/12/21:

  • New version 1.4 is available.
  • Implementation of the functions RfcAppendNewRows, RfcGetRowType, RfcLanguageIsoToSap, RfcLanguageSapToIso and RfcSetCpicTraceLevel – Hint: From this point CCo is not backward compatible, use always the actual SAP NetWeaver RFC library.
  • New examples to create SAP server applications – synchronous and asynchronous.
  • New interprocess communication functions (IPC) to enable implementation of other processes.

2014/12/11:

  • Updated version 1.3 is available.
  • No functional changes, only a few interface changes in the context of bgRFC calls.
  • Many new examples, e.g. VBScript BAPI examples, t/qRFC and bgRFC examples.
  • Checked with actual RFC library patch level 31.
  • Corrected register routine.

2014/09/21:

  • Updated version 1.2 is available.
  • No functional changes, new compilation with advanced header files.
  • Checked with actual RFC library patch level 25.
  • Corrected register routine.

Assigned Tags

      58 Comments
      You must be Logged on to comment or reply to a post.
      Author's profile photo Stefan Schnell
      Stefan Schnell
      Blog Post Author

      Hello community,

      here an example to show how easy it is with CCo to use RFC FMs, here RFC_READ_TABLE:

      '-Begin-----------------------------------------------------------------
      
        '-Directives----------------------------------------------------------
          Option Explicit
      
        '-Constants-----------------------------------------------------------
          Const RFC_OK = 0
      
        '-Sub ReadTableEntries------------------------------------------------
          Sub ReadTableEntries()
       
            '-Variables-------------------------------------------------------
              Dim SAP As CCo.COMNWRFC
              Dim hRFC As Long
              Dim rc As Integer
              Dim hFunc As Long
              Dim hFuncDesc As Long
              Dim hTable As Long
              Dim rowCount As Long
              Dim charBuffer As String
              Dim i As Long
           
            Set SAP = CreateObject("COMNWRFC")
            If IsObject(SAP) Then
       
              hRFC = SAP.RFCOPENCONNECTION("ASHOST=ABAP, " & _  
                "SYSNR=00, CLIENT=001, USER=BCUSER")         If hRFC Then                   hFuncDesc = SAP.RFCGETFUNCTIONDESC(hRFC, "RFC_READ_TABLE")           If hFuncDesc Then             hFunc = SAP.RFCCREATEFUNCTION(hFuncDesc)             If hFunc Then                           rc = SAP.RFCSETCHARS(hFunc, "QUERY_TABLE", "SFLIGHT")               rc = SAP.RFCSETCHARS(hFunc, "DELIMITER", "~")                         If SAP.RFCINVOKE(hRFC, hFunc) = RFC_OK Then                               rc = SAP.RFCGETTABLE(hFunc, "DATA", hTable)                               If SAP.RFCGETROWCOUNT(hTable, rowCount) = RFC_OK Then                                 For i = 1 To rowCount                     rc = SAP.RFCGETCHARS(hTable, "WA", charBuffer, 512)                     Debug.Print charBuffer                   Next                                     End If                                   End If               rc = SAP.RFCDESTROYFUNCTION(hFunc)             End If           End If                   rc = SAP.RFCCLOSECONNECTION(hRFC)         End If         Set SAP = Nothing         End If       End Sub '-End-------------------------------------------------------------------

      Cheers

      Stefan

      Author's profile photo Stefan Schnell
      Stefan Schnell
      Blog Post Author
      Author's profile photo Adelina Pechard
      Adelina Pechard

      Hi Stefan,

      I downloaded RFC library 7.20 and CCo, when I tried the sample script  inside CCo, it failed with message saying that it can't open library sapnwrfc.dll. I searched the RFC library folder and that file isn't there.

      Questions:

      1. which version of RFC library version should I download. I'm sorry if I missed the info  from your post.

      2. Can this FM be access via CCo? COMMON_LOG_READ_T100

      I was trying to use startrfc.exe from command line to query a job to check if it's complete. But from command line it won't let me access it, do you have any idea why?

      C:\rfcsdk\bin>startrfc -3 -h host -s 00 -c 000 -l ENG -u ddic -p pass

      -F COMMON_LOG_READ_T100 -E JOBNAME=RSPARAGENER8M -E JOBLOG=JOBLGX17162900X09514

      RFC Call/Exception: SYSTEM_FAILURE

      Group       Error group 104

      Key         RFC_ERROR_SYSTEM_FAILURE

      Message     The function module "COMMON_LOG_READ_T100" cannot be used for 'remote' calls.

      thank you so much for your help

      Adelina

      Author's profile photo Stefan Schnell
      Stefan Schnell
      Blog Post Author

      Hello Adelina,

      thanks for your reply.

      To your questions:

      1. You find basically information about SAP NW RFC here. The location of the library is described in the note 1056696. Download the version for Windows Server on IA 32bit. It is SAR packed, also you need SAPCAR packer from Support Portal > Software Downloads > Support Packages and Patches > A - Z Index > Character C > SAPCAR
      2. Not really, COMMON_LOG_READ_T100 is not an remote-enabled module, with a little trick you can call it via CCo. But you need a developer key on the target system to do that. Look at the example 0108_ABAPReport.au3 in the AutoIt directory of CCo. This example shows how to define and execute a report outside from SAP. You can use this example to call any not remote-enabled FM and to get the result, to use it in your context - but only on non-production systems.

      Let us know the results.

      Cheers

      Stefan

      Author's profile photo Krzysztof Siwiec
      Krzysztof Siwiec

      Hi Stefan,

      Very good work. But I have 2 issues with using CCo library from VBA:

      1. When the remote module calls an exception is there a way to suppress the CCO messages?

      2. When calling an FM with SAP_GUI visible (SAP_GUI=1 in the connection string), than if a FM calls an exception, then after displaying the error message from inside CCO, VB hangs waiting for the SAP GUI window to be closed manually.

      Chris Siwiec

      Author's profile photo Stefan Schnell
      Stefan Schnell
      Blog Post Author

      Hello Chris,

      thanks for your reply and sorry for my late answer but I was out of office last week.

      To your questions:

      1. Sure, use the property ErrorMsgTarget with the value 1 for OutputDebugString or 2 for RFC_ERROR_INFO structure. If you use 2 you can get the errormessage with the property ErrorKey, look at the example below.
      2. I will check it and send you an answer later.

      Cheers

      Stefan

      '-Begin-----------------------------------------------------------------
      
        '-Directives----------------------------------------------------------
          Option Explicit
      
        '-Constants-----------------------------------------------------------
          Const RFC_OK = 0
      
        '-Variables-----------------------------------------------------------
          Dim SAP, hRFC, rc, hFuncDesc, hFunc, eText
      
        '-Main----------------------------------------------------------------
          Set SAP = CreateObject("COMNWRFC")
          If IsObject(SAP) Then
            hRFC = SAP.RfcOpenConnection("ASHOST=ABAP, SYSNR=00, " & _
              "CLIENT=001, USER=BCUSER")
            If hRFC Then
      
              'SAP.DebugOutput = 1
      
              'SAP.ErrorMsgTarget = 0 'MessageBox
              'SAP.ErrorMsgTarget = 1 'OutputDebugString
              SAP.ErrorMsgTarget = 2 'RFC_ERROR_INFO via property methods
      
              hFuncDesc = SAP.RfcGetFunctionDesc(hRFC, "Z_RFC_EXCEPTION")
              If hFuncDesc Then
                hFunc = SAP.RfcCreateFunction(hFuncDesc)
                If hFunc Then
                  If SAP.RfcInvoke(hRFC, hFunc) <> RFC_OK Then
                    eText = SAP.ErrorKey
                    MsgBox eText
                  End If
                  rc = SAP.RfcDestroyFunction(hFunc)
                End If
              End If
      
              rc = SAP.RfcCloseConnection(hRFC)
            End If
            Set SAP = Nothing
          End If
      
      '-End-------------------------------------------------------------------
      
      '-ABAP program begin----------------------------------------------------
      '
      ' Function Z_RFC_EXCEPTION.
      ' *"--------------------------------------------------------------------
      ' *"*"Local Interface:
      ' *"  EXCEPTIONS
      ' *"      EXCEPTIONTEST
      ' *"--------------------------------------------------------------------
      '
      '  Raise ExceptionTest.
      '
      ' EndFunction.
      '
      '-ABAP program end------------------------------------------------------
      
      Author's profile photo Stefan Schnell
      Stefan Schnell
      Blog Post Author

      Hello Chris,

      to your second question: I tried it with the following script and it works perfect.

      '-Begin------------------------------------------------------------
      
        '-Directives-----------------------------------------------------
          Option Explicit
      
        '-Constants------------------------------------------------------
          Const RFC_OK = 0
      
        '-Variables------------------------------------------------------
          Dim SAP, hRFC, rc, hFuncDesc, hFunc, eText
      
        '-Main-----------------------------------------------------------
          Set SAP = CreateObject("COMNWRFC")
          If IsObject(SAP) Then
            hRFC = SAP.RfcOpenConnection("ASHOST=ABAP, SYSNR=00, " & _
              "CLIENT=001, USER=BCUSER, SAP_GUI=1")
            If hRFC Then
      
              SAP.DebugOutput = 1
              SAP.ErrorMsgTarget = 2
      
              hFuncDesc = SAP.RfcGetFunctionDesc(hRFC, "Z_RFC_EXCEPTION")
              If hFuncDesc Then
                hFunc = SAP.RfcCreateFunction(hFuncDesc)
                If hFunc Then
                  If SAP.RfcInvoke(hRFC, hFunc) <> RFC_OK Then
                    eText = SAP.ErrorKey
                    'MsgBox eText
                  End If
                  rc = SAP.RfcDestroyFunction(hFunc)
                End If
              End If
      
              rc = SAP.RfcCloseConnection(hRFC)
            End If
            Set SAP = Nothing
          End If
      
      '-End--------------------------------------------------------------

      Cheers

      Stefan

      Author's profile photo Krzysztof Siwiec
      Krzysztof Siwiec

      Thank you Stefan,

      This SAP.ErrorMsgTarget option solves the problem. The library works perfectly and stable. I can recommend it to others.

      With regards,

      Chris

      Author's profile photo Former Member
      Former Member

      Really really thanks for sharing your work.  I was trying to wrap the RFC libray but had a very hard time understanding the API calls.

      Do you have a full example using imports and exports parameter and also tables in the same function call?

      Thanks again.

      Author's profile photo Stefan Schnell
      Stefan Schnell
      Blog Post Author

      Hello Fernando,

      sorry for my late reply.

      Not really, there is an example in the ABAP directory of the zip file with import and export. In the other directories with import and table, but not all together in one example. But you can combine the different parts of the examples very easily. That should not be difficult.

      Cheers

      Stefan

      Author's profile photo Florian Keller
      Florian Keller

      Hello Stefan

      First of all thanks for your excellence work. Vielen Dank!

      When I try to load your dll file (on Win7 64), I receive the messasge:

      Problem to load CCo.dll CCo.dll is not a valid Win32-Application. Tryed both:

      rundll32 CCo.dll,RegisterServer DLLPath

      regsvr32 CCo.dll

      Grüsse aus Zürich,

      Florian

      Author's profile photo Stefan Schnell
      Stefan Schnell
      Blog Post Author

      Hello Florian,

      thanks for your reply. I am surprised.

      Please check the CCo.dll:
      Size: 303.104
      Date: 19.09.2014
      MD5: f164995b74d9fb9ced7e9365ae5e5bd8
      CRC32: 51971AF7
      SHA1: ed5006a8a358c940e7f76fa61b52d25ca216b8d8

      Hint: You can register the library with
      runddll32 CCo.dll,RegisterServer %cd%
      Thanks to Bruce for this cool tip.

      I try it in a VM and in my case it works perfect with Windows 7 64-bit.

      Let us know your results.

      Beste Grüsse aus Bonn.
      Stefan

      Author's profile photo Florian Keller
      Florian Keller

      Hello Stefan

      Thanks for your reply. Tryed to register dll from %systemroot%\system32, which didnt worked 🙁 . From another path, with your cmd it worked very well.

      Grüsse aus Zürich,

      Florian

      Author's profile photo Stefan Schnell
      Stefan Schnell
      Blog Post Author

      Hello Florian,

      thanks for your reply. I never try to register a library from Windows system path. It is not necessary to copy and register the library from this path, As you wrote, it works well from any other path.

      Beste Grüsse aus Bonn.

      Stefan

      Author's profile photo Florian Keller
      Florian Keller

      Hello Stefan

      Now Im receive message can't open library sapnwrfc. I've copy this library to system32. Also tryed both Version Winx64 and Win IA32. Both dll same message. I think its because the current PL is 28. Your version is compiled with PL25. There is no possibility for me to get the old one.

      Grüsse aus Zürich,

      Florian

      Author's profile photo Stefan Schnell
      Stefan Schnell
      Blog Post Author

      Hello Florian,

      copy icudt34.dll, icuin34.dll, icuuc34.dll, libicudecnumber.dll, libsapucum.dll and sapnwrfc.dll from your SAR file (NWRFC_28-20004566.SAR) in the same directory as CCo.dll. COM Connector should work now. I have just tried it with the actual PL28 version, in my case it works well.

      Beste Grüsse aus Bonn

      Stefan

      Author's profile photo Florian Keller
      Florian Keller

      Hi Stefan

      Thx. again. I've messed up the x64 and i32 dlls. Now it works!

      Sorry,

      viele Grüsse aus Zürich,

      Florian

      Author's profile photo Hung Fa Hu
      Hung Fa Hu

      Hello stefan,

      I receive message "can't open library sapnwrfc", too.

      And I've copy icudt34.dll, icuin34.dll, icuuc34.dll, libicudecnumber.dll, libsapucum.dll and sapnwrfc.dll in the same directory as CCo.dll, but it's still not work.

      Regards,

      Hugo

      Author's profile photo Stefan Schnell
      Stefan Schnell
      Blog Post Author

      Hello Hugo,

      try this:

      ;-Begin-----------------------------------------------------------------
      
        $hDLL = DllOpen("sapnwrfc.dll")
        If $hDLL <> -1 Then
          $Ver = DllCall($hDLL, "wStr", "RfcGetVersion", "uInt", 0, _
            "uInt", 0, "uInt", 0)
          If @AutoItX64 = 1 Then
            MsgBox(0, "", "AutoIt " & @AutoItVersion & " x64" & @CrLf & _
              "SAPNWRFC " & $Ver[0])
          Else
            MsgBox(0, "", "AutoIt " & @AutoItVersion & " x86" & @CrLf & _
              "SAPNWRFC " & $Ver[0])
          EndIf
          DllClose($hDLL)
        Else
          If @AutoItX64 = 1 Then
            MsgBox(0, "AutoIt x64", "Can't load library")
          Else
            MsgBox(0, "AutoIt x86", "Can't load library")
          EndIf
        EndIf
      
      ;-End-------------------------------------------------------------------
      

      What do you see?

      Something like this:

      Unbenannt.JPG

      Be sure that you use the correct AutoIt version - x86.

      Let us know your result.

      Cheers

      Stefan

      Author's profile photo Former Member
      Former Member

      Hi Stefan,

      Thanks for your reply.

      Please see the below picture for result.

      /wp-content/uploads/2015/10/1_802509.png/wp-content/uploads/2015/10/2_802510.png/wp-content/uploads/2015/10/1_802509.png

      Many Thanks!

      Hugo Peng

      Author's profile photo Stefan Schnell
      Stefan Schnell
      Blog Post Author

      Hello community,

      Hugo sent me an e-mail. All problems are now solved, it was a mix-up between x64 and x86 library.

      Good luck to Hugo and his projects.

      Cheers

      Stefan

      Author's profile photo Former Member
      Former Member

      Hi Stefan,

      I've successfully written a simple application using your CCo wrapper, however I was wondering if you have any suggestions for dealing with the handle leak in rfcOpenConnection? It appears that it leaks handles when called, and is most noticeable when there is a network outage - if you loop the rfcOpenConnection call then it leaks 1 to 4 handles every connection attempt, and even if the network comes back up it may not connect again due to having too many handles open. As the handle is never passed back from the call if there is a connection error there is nothing to pass to rfcCloseConnection to clean up the handles.

      It's worse on Windows 7 than on Windows Server due to DEP - after around 100 failed connections it causes a StackHash crash in the application 🙁

      I can code round it by moving the RFC calls to a separate executable and having the parent service application call that in it's cycle, and letting Windows deal with cleaning up any handles that are not released by the DLL, but it's not an elegant solution and has an impact on the server in that it has to go through all the work of creating and destroying processes just to deal with a leak that shouldn't be there.

      I see other people have posted about the leak a few years ago with no response from SAP, so I'm not holding out much hope for this to be fixed by them, but is there anything in your CCo that could mitigate this issue by adding a method to force the DLL resources to be flushed and reset? My C++ knowledge is limited to reusing existing DLLs and building code based on examples, so I'm not sure if this is even possible. Most of the application codebase in the company I work for is still VB6 based, which is why I have been looking at CCo as possible solution to implementing SAP RFC calls directly within our applications rather than relying on calling external proxy processes.

      Regards,

      Dan

      Author's profile photo Stefan Schnell
      Stefan Schnell
      Blog Post Author

      Hello Daniel,

      thank you for your reply and sorry for my late answer - vacation and business stress.

      I try to reproduce your problem with the following source:

      '-Begin-----------------------------------------------------------------
      
        '-Directives----------------------------------------------------------
          Option Explicit
      
        '-Constants-----------------------------------------------------------
          Const RFC_OK = 0
      
        '-Sub Main------------------------------------------------------------
          Sub Main()
      
            '-Variables-------------------------------------------------------
              Dim SAP, SAPHelp, rc, hFuncDesc, hFunc, hRFC(149), i
      
            Set SAP = CreateObject("COMNWRFC")
            Set SAPHelp = CreateObject("COMNWRFCHELP")
            If IsObject(SAP) And IsObject(SAPHelp) Then
      
              SAP.ErrorMsgTarget = 1
      
              For i = 0 To 149
                hRFC(i) = SAP.RfcOpenConnection("ASHOST=ABAP, SYSNR=00, " & _
                  "CLIENT=000, USER=BCUSER, PASSWD=minisap")
                If hRFC(i) Then
                  SAPHelp.DebugPrint "Open connection successful (" & _
                    CStr(i) & ")"
                  If SAP.RfcPing(hRFC(i)) = RFC_OK Then
                    SAPHelp.DebugPrint "Ping successful (" & CStr(i) & ")"
                  Else
                    SAPHelp.DebugPrint "Ping not successful (" & CStr(i) & ")"
                  End If
                Else
                  SAPHelp.DebugPrint "Open connection not successful (" & _
                    CStr(i) & ")"
                End If
              Next
      
              '---------------------------------------------------------------
              '-
              '- Here I break the communication
              '- to the application server manually
              '-
              '---------------------------------------------------------------
                MsgBox "Break connection"
      
              For i = 0 To 149
                If SAP.RfcPing(hRFC(i)) = RFC_OK Then
                  SAPHelp.DebugPrint "Ping successful"
                Else
                  SAPHelp.DebugPrint "Ping not successful"
                End If
              Next
      
              For i = 0 To 149
                If SAP.RfcCloseConnection(hRFC(i)) = RFC_OK Then
                  SAPHelp.DebugPrint "Close connection successful (" & _
                    CStr(i) & ")"
                Else
                  SAPHelp.DebugPrint "Close connection not successful (" & _
                    CStr(i) & ")"
                End If
              Next
      
              Set SAP = Nothing
              Set SAPHelp = Nothing
            End If
      
            '-----------------------------------------------------------------
            '-
            '- Here I reconnect the communication
            '- to the application server manually
            '-
            '-----------------------------------------------------------------
                MsgBox "Reconnect"
      
            Set SAP = CreateObject("COMNWRFC")
            Set SAPHelp = CreateObject("COMNWRFCHELP")
            If IsObject(SAP) And IsObject(SAPHelp) Then
      
              SAP.ErrorMsgTarget = 1
              Erase hRFC
      
              For i = 0 To 99
                hRFC(i) = SAP.RfcOpenConnection("ASHOST=ABAP, SYSNR=00, " & _
                  "CLIENT=000, USER=BCUSER, PASSWD=minisap")
                If hRFC(i) Then
                  SAPHelp.DebugPrint "Open connection successful (" & _
                    CStr(i) & ")"
                Else
                  SAPHelp.DebugPrint "Open connection not successful (" & _
                    CStr(i) & ")"
                End If
              Next
      
              For i = 0 To 99
                If SAP.RfcPing(hRFC(i)) = RFC_OK Then
                  SAPHelp.DebugPrint "Ping successful (" & CStr(i) & ")"
                Else
                  SAPHelp.DebugPrint "Ping not successful (" & CStr(i) & ")"
                End If
              Next
      
              For i = 0 To 99
                If SAP.RfcCloseConnection(hRFC(i)) = RFC_OK Then
                  SAPHelp.DebugPrint "Close connection successful (" & _
                    CStr(i) & ")"
                Else
                  SAPHelp.DebugPrint "Close connection not successful (" & _
                    CStr(i) & ")"
                End If
              Next
      
              Set SAP = Nothing
              Set SAPHelp = Nothing
            End If
      
          End Sub
      
        '-Main----------------------------------------------------------------
          Main
      
      '-End-------------------------------------------------------------------

      At first I open 100 connections to an SAP system parallel - later 150.

      001.JPG

      All works as expected. But if I open, after the reconnection, 100 new connections, I got some errors, but not in the context of the presentation server. In the context of the application server I got the error "Roll-out failed".

      002.JPG

      The application works well - I have no crashes and I can't find leaks, but the SAP GUI for Windows opens a dialog, it seems to be another problem. I will try it with another SAP release and another SAP GUI for Windows version and post later my results.

      Please check it and let us know your results.

      Cheers

      Stefan

      Author's profile photo Stefan Schnell
      Stefan Schnell
      Blog Post Author

      Hello Daniel,

      I try the program with a newer SAP release 7.31 with 150 parallel connections and all works well.

      003.JPG

      I open 150 connections, break the connection to the SAP system and get a lot of errors with the ping and close connection command. Then I open 100 connections, call a ping and close connection command without any problems. So I handle 250 connections in one program context.

      But this don't answer your question - in consideration to my results it seems to be a problem of the application server. I any case CCo works well, with and without destroying the COMNWRFC object.

      This means, it is not necessary to flush and reset the CCo program context on the presentation server. Check this VBScript program in the context of your application server and let us know your results.

      Which programming language do you use?

      What is version of your application server?

      Cheers

      Stefan

      Author's profile photo Former Member
      Former Member

      Hi Stefan,

      Thanks for the reply and your attempts to reproduce this issue. I've actually already worked around the problem by moving the SAP communication to a separate executable which is called as required, this solves the handle leak by having Windows clean it up as part of the process cleanup after execution has completed.

      I'm currently using VB6 SP6 for application programming, and the SAP NW RFC SDK version 7.20 patch 613 changelist 1492427 as this is the version that was provided by the company I am developing the application for. The application we've created runs as a Windows service on a server that does not have the SAP GUI installed, it's purely using the RFC SDK.

      What we are seeing is that after opening and closing connections successfully in our service application over around 24 hours, with about 100 connections in total, we start getting a timeout trying to open further connections and the handle count has raised in the service by around 2-3 handles per connection attempt. At this point we found that stopping and restarting the service temporarily "fixed" the issue, but is not an ideal solution as it would not be possible to accurately determine if the timeout connection was due to the network being down, SAP not responding, or some other factor, rather than the result of the inability to open further connections. This was on a Windows 2008 R2 Server system, as I said on Windows 7 system it would actually cause a StackHash crash in DEP and render the application useless.

      It's pretty easy to replicate the issue by simply using a connection string for a server that doesn't exist, as this will prevent the connection succeeding and cause the SAP RFC to leak handles. Keep repeating and you can see the handle count rise, especially obvious if you have Performance Monitor running charting the handle count for the application process.

      I have requested a later version of the SAP NW RFC SDK from our customer in order to test if this has been fixed, but so far they have not been able to get their SAP team provide them with it; unfortunately being a large global company trying to get things moving takes a lot of effort.

      Regards,

      Dan

      Author's profile photo Stefan Schnell
      Stefan Schnell
      Blog Post Author

      Hello Daniel,

      I tried it with 25 and 50 failed connections but the count of handles seems to be okay:

      001.JPG

      002.JPG

      003.JPG

      004.JPG

      005.JPG

      The count of handles is constant 227.

      '-Begin-----------------------------------------------------------------
      
        '-Directives----------------------------------------------------------
          Option Explicit
      
        '-Constants-----------------------------------------------------------
          Const RFC_OK = 0
      
        '-Sub Main------------------------------------------------------------
          Sub Main()
      
            '-Variables-------------------------------------------------------
              Dim SAP, SAPHelp, rc, hFuncDesc, hFunc, hRFC(149), i
      
            Set SAP = CreateObject("COMNWRFC")
            Set SAPHelp = CreateObject("COMNWRFCHELP")
            If IsObject(SAP) And IsObject(SAPHelp) Then
      
              SAP.ErrorMsgTarget = 1
      
              MsgBox "Measure point start"
      
              For i = 0 To 49
                hRFC(i) = SAP.RfcOpenConnection("ASHOST=BIRNE, SYSNR=00, " & _
                  "CLIENT=000, USER=HUGO, PASSWD=bambi")
                If hRFC(i) Then
                  SAPHelp.DebugPrint "Open connection successful (" & _
                    CStr(i) & ")"
                  If SAP.RfcPing(hRFC(i)) = RFC_OK Then
                    SAPHelp.DebugPrint "Ping successful (" & CStr(i) & ")"
                  Else
                    SAPHelp.DebugPrint "Ping not successful (" & CStr(i) & ")"
                  End If
                Else
                  SAPHelp.DebugPrint "Open connection not successful (" & _
                    CStr(i) & ")"
                End If
                MsgBox "Measure point"
              Next
      
              For i = 0 To 49
                If SAP.RfcCloseConnection(hRFC(i)) = RFC_OK Then
                  SAPHelp.DebugPrint "Close connection successful (" & _
                    CStr(i) & ")"
                Else
                  SAPHelp.DebugPrint "Close connection not successful (" & _
                    CStr(i) & ")"
                End If
              Next
      
              MsgBox "Measure point end"
      
              Set SAP = Nothing
              Set SAPHelp = Nothing
             
              MsgBox "End"
             
            End If
      
          End Sub
      
        '-Main----------------------------------------------------------------
          Main
      
      '-End-------------------------------------------------------------------

      Cheers

      Stefan

      Author's profile photo Former Member
      Former Member

      I think I can see what is happening now. The service application is being built in a modular way, utilising classes that are initialised and then terminated in the service timer event. My class is creating the CCo object at the time the OpenConnection method is called, and destroying it when CloseConnection is called, as this was a requirement of the developer of the main service code as they didn't want to keep objects instantiated outside of the timer.

      However, it looks like CCo itself could be the problem in this case. I wrote a really simple executable in VB6 that does this:

      Private Sub Command1_Click()
      
          Dim rc As Long, hConnHandle As Long, iLoop  As Integer
          Dim oSAP As CCo.COMNWRFC
      
          For iLoop = 1 To 500
      
              Set oSAP = New CCo.COMNWRFC
              oSAP.ERRORMSGTARGET = 2
         
              hConnHandle = oSAP.RFCOPENCONNECTION("ASHOST=saphost.demo.local, SYSID=INP, SYSNR=00, CLIENT=100, USER=MyUser, PASSWD=MyPassword")
             
              If hConnHandle = 0 Then
                'could not open connection, cannot call RFCCLOSECONNECTION as there is no connection handle
              Else
               'close the connection
                  rc = oSAP.RFCCLOSECONNECTION(hConnHandle)
              End If
      
              Set oSAP = Nothing
      
          Next
         
          MsgBox "Complete"
      
      End Sub

      which gets as far as loop 125 and then crashes, with the handle count steadily raising. Here's a screenshot showing the performance monitor chart set to display the handle count from the executable every 1 second (the 65 second flat line at the start is something else I'm looking into, for some odd reason on my development system calling New CCo.COMNWRFC causes the application to hang for 65 seconds - always exactly 65 seconds - but this doesn't occur when it's run on the Windows 2008 R2 Server).

      handle chart and crash details.png

      So then I modified the code to move the object creation and destruction to outside of the loop:

      Private Sub Command1_Click()
      
          Dim rc As Long, hConnHandle As Long, iLoop  As Integer
          Dim oSAP As CCo.COMNWRFC
      
          Set oSAP = New CCo.COMNWRFC
          oSAP.ERRORMSGTARGET = 2
      
          For iLoop = 1 To 500
      
         
              hConnHandle = oSAP.RFCOPENCONNECTION("ASHOST=saphost.demo.local, SYSID=INP, SYSNR=00, CLIENT=100, USER=MyUser, PASSWD=MyPassword")
             
              If hConnHandle = 0 Then
                'could not open connection, cannot call RFCCLOSECONNECTION as there is no connection handle
              Else
               'close the connection
                  rc = oSAP.RFCCLOSECONNECTION(hConnHandle)
              End If
      
          Next
      
          Set oSAP = Nothing
         
          MsgBox "Complete"
      
      End Sub

      and this successfully ran the full 500 loops with only 2 or 3 extra handles being created. Here's a screenshot at loop 253:

      handle chart for single instance.png

      so it's looking like the leak may well be in CCo itself, not in the SAP NW RFC SDK, although without knowing your code is calling the SDK I'm only guessing here. If you only initialise the RFC SDK when your class is initialised then it's possible that the leak is in the SAP RFC initialisation/terminate code, but is not an issue when the DLL is only initialised once.

      At least this exercise has demonstrated that we can move the CCo wrapper class we have written back into the main service code, and simply make sure that we only instantiate the class once; so in turn only create the CCo object once, rather than in each iteration of the service timer loop.

      If moving to the SAP NW RFC SDK 7.3 would allow the CCo object to be initialised/destroyed repeatedly without leaking handles this would at least mean that we would not have to highlight in our documentation that the class must not be instantiated repeatedly in any future developments.

      Regards,

      Dan

      Author's profile photo Stefan Schnell
      Stefan Schnell
      Blog Post Author

      Hello Dan,

      thanks for your reply. You are right, CCo loads the RFC library on instanziation of the class and frees it on termination of the object. I will check it and post my results. Under this aspect it seems to be useful to "undock" the instanziation of the class and the loading of the library as well as the termination of the object and the freeing of the library. I must think about over, the pros and cons.

      Cheers

      Stefan

      Author's profile photo Stefan Schnell
      Stefan Schnell
      Blog Post Author

      Hello Dan,

      I changed my test program and create now 150 objects, and in the context of this objects I open for each object a connection, also 150 open connections:

      '-Begin-----------------------------------------------------------------
      
        '-Directives----------------------------------------------------------
          Option Explicit
      
        '-Constants-----------------------------------------------------------
          Const RFC_OK = 0
      
        '-Sub Main------------------------------------------------------------
          Sub Main()
      
            '-Variables-------------------------------------------------------
              Dim SAP(149), SAPHelp(149), rc, hFuncDesc, hFunc, hRFC(149), i
      
            MsgBox "Begin"
      
            For i = 0 To 149
      
              Set SAP(i) = CreateObject("COMNWRFC")
              Set SAPHelp(i) = CreateObject("COMNWRFCHELP")
              If IsObject(SAP(i)) And IsObject(SAPHelp(i)) Then
      
                SAP(i).ErrorMsgTarget = 1
      
                hRFC(i) = SAP(i).RfcOpenConnection("ASHOST=BIRNE, SYSNR=00, " & _
                  "CLIENT=000, USER=HUGO, PASSWD=bambi")
                If hRFC(i) Then
                  SAPHelp(i).DebugPrint "Open connection successful (" & _
                    CStr(i) & ")"
                  If SAP(i).RfcPing(hRFC(i)) = RFC_OK Then
                    SAPHelp(i).DebugPrint "Ping successful (" & CStr(i) & ")"
                  Else
                    SAPHelp(i).DebugPrint "Ping not successful (" & CStr(i) & ")"
                  End If
                Else
                  SAPHelp(i).DebugPrint "Open connection not successful (" & _
                    CStr(i) & ")"
                End If
              End If
           
            Next
      
            MsgBox "Middle"
      
            For i = 0 To 149
      
              If SAP(i).RfcCloseConnection(hRFC(i)) = RFC_OK Then
                SAPHelp(i).DebugPrint "Close connection successful (" & _
                  CStr(i) & ")"
              Else
                SAPHelp(i).DebugPrint "Close connection not successful (" & _
                  CStr(i) & ")"
              End If
      
              Set SAP(i) = Nothing
              Set SAPHelp(i) = Nothing
      
            Next
      
            MsgBox "End"
      
          End Sub
      
        '-Main----------------------------------------------------------------
          Main
      
      '-End-------------------------------------------------------------------

      But all works well, no crashes or something else.

      001.JPG

      Is there maybe a problem of programming language?

      Here the result with the performance monitor.

      002.JPG

      The count of handle is constant. It seems that CCo with NW RFC library works in both cases without errors.

      Cheers

      Stefan

      Author's profile photo Former Member
      Former Member

      That script causes a StackHash crash for me.

      I adjusted the script to match the VB6 version, in that the the object is created and destroyed inside the loop. Note that my connection string is the same as yours, but this means that I will *always* get a connection failure. I believe the failure is possibly the source of the problem, as when a connection cannot be opened there is no handle to pass to the method to close the connection, the assumption is that no handle exists. If you change your connection string to point to a non-existent server, does that cause a handle leak for you?

      '-Begin-----------------------------------------------------------------
      
        '-Directives----------------------------------------------------------
          Option Explicit
      
        '-Sub Main------------------------------------------------------------
          Sub Main()
      
            '-Variables-------------------------------------------------------
              Dim SAP, rc, hRFC, i
      
            MsgBox "Begin"
      
            For i = 0 To 149
      
              Set SAP = CreateObject("COMNWRFC")
              If IsObject(SAP) Then
      
                SAP.ErrorMsgTarget = 2
      
                hRFC = SAP.RfcOpenConnection("ASHOST=BIRNE, SYSNR=00, " & _
                  "CLIENT=000, USER=HUGO, PASSWD=bambi")
                If hRFC Then
                  WScript.Echo "Open connection successful (" & _
                    CStr(i) & ")"
                      
                     SAP.RfcCloseConnection(hRFC)
                Else
                  WScript.Echo "Open connection not successful (" & _
                    CStr(i) & ")"
                End If
              End If
               
                Set SAP = Nothing
           
            Next
      
            MsgBox "End"
      
          End Sub
      
        '-Main----------------------------------------------------------------
          Main
      
      '-End-------------------------------------------------------------------
      

      and this time the crash happens on loop 123, again a StackHash crash. And the performance monitor chart shows the handle count climbing, the flat line at the end is due to the monitor continuing after the script had crashed.

      handle chart and crash details for vbscript version.png

      As the only difference here is probably that you are using a different version of the SAP NW RFC SDK this suggests the leak is in the SDK, does it not? Or are you using a later version of CCo than the one available on your website?

      Dan

      Author's profile photo Stefan Schnell
      Stefan Schnell
      Blog Post Author

      Hello Dan,

      with your program I get the same results. I try an equal procedure in another programming language, without CCo and I get also the same result.

      001.JPG

      As you wrote here, it seems to be a problem inside the RFC library. My suggestion: Report a product error in the support portal.

      Cheers

      Stefan

      Author's profile photo Former Member
      Former Member

      Hi Stefan,

      Thanks for confirming that it appears to be a bug in the RFC library. I'll ask the SAP team at the company we're developing this application for to report this issue as I don't have access to the support portal myself.

      Regards,

      Dan

      Author's profile photo Stefan Schnell
      Stefan Schnell
      Blog Post Author

      Hello Daniel,

      I think I solve your problem.

      I implemented three new functions in the helper class of CCo:

      • Property Get cntOpenHandles() As Long
        Gets the count of open handles of the process
      • Property Get lstOpenHandles() As String
        Gets a list of all open handles of the process
      • Method CloseHandle(ByVal hObject As Dword) As Long
        Closes an open object handle

      With this possibilities you can permanently close the unused handles, to handle the handle leak of the NW RFC library.

      😀

      In my test program I detect the open handles at the first loop execution. After the second loop execution I detect the difference between the first and the actual loop execution. This difference is the potential to close it via CloseHandle - and it works for this case.

      '-Begin-----------------------------------------------------------------
      
        '-Directives----------------------------------------------------------
          Option Explicit
      
        '-Constants-----------------------------------------------------------
          Const RFC_OK = 0
      
        '-Sub Main------------------------------------------------------------
          Sub Main()
      
            '-Variables-------------------------------------------------------
              Dim SAP, SAPHelp, rc, hRFC, i, strRC, arrHandles, arrHandles2
              Dim j, k, Found
      
            MsgBox "Start"
      
            For i = 0 To 49
      
              Set SAP = CreateObject("COMNWRFC")
              Set SAPHelp = CreateObject("COMNWRFCHELP")
      
              If IsObject(SAP) And IsObject(SAPHelp) Then
      
                SAPHelp.DebugPrint "Open handles: " & _
                  CStr(SAPHelp.cntOpenHandles)
      
                  If i = 1 Then
                    strRC = SAPHelp.lstOpenHandles
                    arrHandles = Split(strRC, ";")
                  End If
      
                SAP.ErrorMsgTarget = 2
      
                hRFC = SAP.RfcOpenConnection("ASHOST=ABAP, SYSNR=00, " & _
                  "CLIENT=001, USER=BCUSER, PASSWD=minisap")
                If hRFC Then
                  SAPHelp.DebugPrint "Open connection successful (" & _
                    CStr(i) & ")"
                  rc = SAP.RfcCloseConnection(hRFC)
                Else
                  SAPHelp.DebugPrint "Open connection not successful (" & _
                    CStr(i) & ")"
                End If
      
                If i > 2 Then
                  strRC = SAPHelp.lstOpenHandles
                  arrHandles2 = Split(strRC, ";")
      
                  For j = 0 To UBound(arrHandles2) - 1
                    Found = vbFalse
                    For k = 0 To UBound(arrHandles) - 1
                      If arrHandles2(j) = arrHandles(k) Then
                        Found = vbTrue
                      End If
                    Next
                    If Not Found Then
                      rc = SAPHelp.CloseHandle(arrHandles2(j))
                      SAPHelp.DebugPrint "Close handle (" & arrHandles2(j) & _
                        ") = " & CStr(rc)
                    End If
                  Next
      
                End If
      
                SAPHelp.DebugPrint "Open handles: " & _
                  CStr(SAPHelp.cntOpenHandles)
      
                Set SAP = Nothing
                Set SAPHelp = Nothing
      
              End If
      
            Next
      
          End Sub
      
        '-Main----------------------------------------------------------------
          Main
      
      '-End-------------------------------------------------------------------
      

      With this test program I get this result:

      001.JPG

      As you can see, the count of open handles is constant.

      You can download an experimental version of CCo from here.

      Please try it in your case and let us know your results.

      Cheers

      Stefan

      Author's profile photo Former Member
      Former Member

      Hi Stefan,

      Thanks for the update. I'll see if I can test it today, if not it will be early next week.

      I'm just wondering though - if having this additional step to clean up handles solves the issue, can't you simply add the same functionality to the COMNWRFC destructor? That way it ensures that CCo itself cleans up any open handles when it is no longer required, rather than having to rely on the developer to clean up the handles manually.

      Regards,

      Dan

      Author's profile photo Stefan Schnell
      Stefan Schnell
      Blog Post Author

      Hello Daniel,

      it is at the moment not really possible to put the clean-up routine in the destructor - experimental Version. Please try the method and tell me if it works. If all works correct in your case, we can talk about an automatic routine via a switch.

      Cheers

      Stefan

      Author's profile photo Former Member
      Former Member

      Hi Stefan,

      I'm testing the experimental DLL today, however I have a query about your example code - why do you obtain a list of handles when creating the first instance, and then compare this to the handle list on each subsequent call and close the handles that were not in the first call? Is this so that the handles to the first load of the SAP RFC DLL are retained? Why does it store the handle list when i = 1 rather than 0? And why does it clear handles only from i > 2 rather than i > 0?

      I've run it 4 times to far. In each case I still got a StackHash crash on the 123rd creation of the CONMWRFC object.

      I'm doing all my testing against a hostname that does not exist, as there appears to be more leakage in the RFC DLLs when a connection cannot be made.

      I'm using a slightly modified version of your script, I've increased the loop count to 149 (you won't see a crash with an upper limit of only 49), and using WScript.Echo to output the handle counts to the console.

      Regards,

      Dan

      Author's profile photo Stefan Schnell
      Stefan Schnell
      Blog Post Author

      Hi Dan,

      thanks for your reply.

      I am careful, so I get all open handles with the 2nd execution of the loop. It is necessary because otherwise you close necessary handles of the basic process and this is dangerous for your program, it could crashes.

      The different count of handles could have their reasons in the time difference between the measurement point of CCo and the Performance Monitor.

      Here my results with the test with 150 failed connections. As you can see, count of open handles is constant.

      result.JPG

      Cheers

      Stefan

      Author's profile photo Former Member
      Former Member

      Hi Stefan,

      That's odd, as if I take your exact last script above and change the loop to 149, and change the debug output to WScript.Echo so I can the messages in the console, it consistently crashes on the 123rd loop with a StackHash crash in BEX on Windows 7 Pro with SP1. The handle count remains flat, but something else appears to be causing it to crash - this error appears to be related to trying to access memory outside of the address space allocated to the application.

      I've rewritten my original class to create the COMNWRFC object in the Initialise event, and destroy it in the Terminate event, and the calling service application is only creating the class once when it starts. This is now running on our server and I'll be keeping a close eye on it over the next few days to see if we run into any issues, but the simple test script from last week that doesn't destroy the object in the loop seemed to run without issues. I'm also going to try running it in the test script locally with a few thousands loops to see if there is a potential for long term issues.

      Regards,

      Dan

      Author's profile photo Stefan Schnell
      Stefan Schnell
      Blog Post Author

      Hello Dan,

      here new knowledge. I checked the behaviour with another programming language, AutoIt. I use the following program, but without the @AutoItX64 requests. These are later implementations, but now the program runs without any errors in x86 and x64 environments.

      ;-Begin-----------------------------------------------------------------
      
        ;-Directives----------------------------------------------------------
          AutoItSetOption("MustDeclareVars", 1)
      
        ;-Constants-----------------------------------------------------------
          Const $RFC_OK = 0
      
        ;-Sub Main------------------------------------------------------------
          Func Main()
      
            ;-Variables-------------------------------------------------------
              Local $SAP, $SAPHelp, $rc, $hRFC, $i, $ListOpenHandles
      
            MsgBox(0, "", "Start")
      
            For $i = 0 To 149
      
              $SAP = ObjCreate("COMNWRFC")
              $SAPHelp = ObjCreate("COMNWRFCHELP")
      
              If IsObj($SAP) And IsObj($SAPHelp) Then
      
                $SAPHelp.DebugOutput = 1
      
                If @AutoItX64 = 0 Then
                  $SAPHelp.DebugPrint("Open handles: " & _
                    String($SAPHelp.cntOpenHandles))
                  If $i = 1 Then
                    $ListOpenHandles = $SAPHelp.ListOpenHandles()
                  EndIf
                EndIf
      
                $SAP.ErrorMsgTarget = 2
      
                $hRFC = $SAP.RfcOpenConnection("ASHOST=ABAP, SYSNR=00, " & _
                  "CLIENT=001, USER=BCUSER, PASSWD=minisap")
                If $hRFC Then
                  $SAPHelp.DebugPrint("Open connection successful (" & _
                    String($i) & ")")
                  $rc = $SAP.RfcCloseConnection($hRFC)
                Else
                  $SAPHelp.DebugPrint("Open connection not successful (" & _
                    String($i) & ")")
                EndIf
      
                If @AutoItX64 = 0 Then
                  If $i >= 2 Then
                    $SAPHelp.CloseDiffHandles($ListOpenHandles)
                  EndIf
                  $SAPHelp.DebugPrint("Open handles: " & _
                    String($SAPHelp.cntOpenHandles))
                EndIf
      
                $SAP = 0
                $SAPHelp = 0
      
              EndIf
      
            Next
      
          EndFunc
      
        ;-Main----------------------------------------------------------------
          Main()
      
      ;-End-------------------------------------------------------------------

      The results:

      1. If I use x64 version the program crashes at the third loop. So I disable CloseDiffHandles and all works well - no handle leak.
        AutoIt_x64.jpg
      2. I use the same program with x86 version of AutoIt.
        AutoIt_x86.JPG
      3. So I use the the correction function of CCo and all works well.
        AutoIt_x86_2.JPG

      It seems that the handle leak is only present in 32bit processes, and not in 64bit processes. The method cntOpenHandles works only correct in 32bit processes, also CloseDiffHandles. With this experience is clear, that these methods could never be part of the constructor or destructor. The calling program must decide to use the correction routines.

      Cheers

      Stefan

      Author's profile photo Former Member
      Former Member

      Hi Stefan,

      When you've been testing using VBScript have you been using the 32-bit version of cscript/wscript? I have W7 64-bit, but I have been explicitly using the cscript.exe in c:\windows\syswow64 as this is the 32-bit version, and the CCo I have is only 32-bit so cannot be used with the default 64-bit version (as the path normally points to c:\windows\system32 running any VBS script without specifying the syswow64 path will run the 64-bit script engine). I only have access to the 32-bit SAP NW RFC DLLs, and my host application is in VB6 which is 32-bit anyway, so all of my testing has been with 32-bit throughout.

      I still can't get your last VBScript example to run without crashing at the 123rd loop. So far my host application has been running for a few days without issues, as it's now creating the CCo object in the application startup routine, and not creating/destroying in the main loop which runs every 5 seconds or so. Handles and threads have been constant, idle memory has been looking pretty constant too, and in my stripped down VBScript testing on Monday I got to 25,000 loops of trying to open a connection to a non-existent SAP host without any apparent issues - I'll look at scheduling a longer loop later in the week to see whether longer term there might be other issues. As I don't have direct access to a SAP server for testing I have no idea if there are side effects related to successfully opening connections, but so far the SAP admin team I'm working with haven't reported any issues at their end and the application has been running for about 36 hours now, previously it would start being unable to open new connections after about 24 hours.

      Thanks for your help looking into this, your testing and confirmation of the leak at least pointed me in the direction of moving the object out of the loop and may well have solved the issue for me. The application is still in a testing state, but so far so good 🙂

      Dan

      Author's profile photo Stefan Schnell
      Stefan Schnell
      Blog Post Author

      Hello Dan,

      thanks for your reply.

      CCo is a 32-bit library and it uses the 32-bit version of SAP NW RFC library, but you can use CCo seamless with 64-bit applications without any problems.

      Okay, I think you made a good decision to solve your problem on another way. As you can see it is very tricky to use a correction via a library. I will clean up all this stuff from the library.

      Does your collegue opens an OSS note for the handle leak?

      Cheers

      Stefan

      Author's profile photo Former Member
      Former Member

      Hi Stefan,

      I've asked him to raise it, but nothing done so far as I'm aware. Unfortunately the SAP guy I'm working with is under pressure to hit various project deadlines so may well not get chance to do this for a while.

      Regards,

      Dan

      Author's profile photo Former Member
      Former Member

      Hi Stefan, Wonderful article.Great work

      Author's profile photo Ziv Markovich
      Ziv Markovich

      Great work Stefan , very usfull

      Thanks for sharing



      BR

      Ziv



      Author's profile photo Krzysztof Siwiec
      Krzysztof Siwiec

      Can CCo be used with Office 64 bit?

      If not, will you prepare 64 bit version based on 64 bit version of RFC library?

      With regards Chris

      Author's profile photo Stefan Schnell
      Stefan Schnell
      Blog Post Author

      Hello Chris,

      sure, you can use CCo library with 64bit Office VBA programs, but there are two limits:

      1. It is not possible to reference CCo library inside 64bit VBA IDE, you can find here more information, so you can't use e.g. code completion.
        Tip: Develop your program with a 32bit VBA IDE.

      2. To use CCo library with 64bit VBA programs you can use the following snippet:
        'If Application.Version >= 14 Then
          #If Win64 Then
            Dim SAP As Object
          #Else
            Dim SAP As CCo.COMNWRFC
          #End If
        'Else
        '  Dim SAP As CCo.COMNWRFC
        'End If

        With this code you can use your VBA programs with both, 32bit and 64bit, seamlessly.

      Enjoy it.

      Cheers

      Stefan

      Author's profile photo Former Member
      Former Member

      Hi Stefan,

      I was wondering if you'd be able to expand on the "patch level 38" note in the latest release - how does this relate to the SAP NW RFC DLL version numbering? For instance, my sapnwrfc.dll file has a Product version of 720, patch 613, changelist 1492427. The file version is 7200.613.22.50635. I can find no reference to a patch level; would this be the equivalent of the revision number 22 in the file version that I have?

      Regards,

      Dan

      Author's profile photo Stefan Schnell
      Stefan Schnell
      Blog Post Author

      Hello Dan,

      thanks for your reply.

      I use actual the version 7210.614.24.52788. If you call the function RfcGetVersion you get major, minor and patchlevel in the parameters and it delivers a full version string back. On this way I get the patchlevel.

      /wp-content/uploads/2015/11/001_835880.jpg

      Cheers

      Stefan

      Author's profile photo Former Member
      Former Member

      Hi Stefan,

      Thanks for the quick reply. It looks like I'm on MajorVersion 7200, MinorVersion 0, PatchLevel 22. I'd suspected that I didn't have the latest version, but the SAP team I'm working with assured me that it is. At least now I have proof 🙂

      Regards,

      Dan

      Author's profile photo Stefan Schnell
      Stefan Schnell
      Blog Post Author

      Hello Dan,

      the actual version is from 13.11.2015 from the support portal:

      /wp-content/uploads/2015/11/001_835888.jpg

      Cheers

      Stefan

      Author's profile photo Former Member
      Former Member

      Thanks again Stefan. I've asked my contact in our SAP team to try to get this file, so far he's not having much luck and the only patch level 38 file he can find is for OS/400. I don't think he's looking on the right page of the software download list ... 😥

      Dan

      Author's profile photo Stefan Schnell
      Stefan Schnell
      Blog Post Author

      Hello Dan,

      you can find the files here:

      Support Portal > Software Downloads > Support Packages and Patches > Browse Download Catalog > SAP Connectors > SAP NW RFC SDK > SAP NW RFC SDK 7.20 > Windows Server on IA32 32bit

      Cheers

      Stefan

      Author's profile photo Rainer Lutz
      Rainer Lutz

      Hi Stefan,

      is it possible to use this with SSO?

      Kind regards,

      Rainer

      Author's profile photo Stefan Schnell
      Stefan Schnell
      Blog Post Author

      Hello Rainer,

      I have never tried it, but it should.

      '-Begin-----------------------------------------------------------------
      
        '-Directives----------------------------------------------------------
          Option Explicit
      
        '-Variables-----------------------------------------------------------
          Dim SAP, hRFC, rc
      
        '-Main----------------------------------------------------------------
          Set SAP = CreateObject("COMNWRFC")
          If IsObject(SAP) Then
      
            hRFC = SAP.RfcOpenConnection("ASHOST=CRT, SYSNR=63, " & _
              "PASSWD= , CLIENT=099, MYSAPSSO2=AjExMDAC4711xAw...")
            If hRFC Then
      
              MsgBox "Connected"
      
              rc = SAP.RfcCloseConnection(hRFC)
            End If
            Set SAP = Nothing
          End If
      
      '-End-------------------------------------------------------------------

      Let us know your results.

      Cheers

      Stefan

      Author's profile photo Rainer Lutz
      Rainer Lutz

      Hi Stefan,

      unfortunately i do not use mysapsso2. Instead we have the secure login server ( SPNEGO )

      Any idea? I have a secure login client installed. Therefore i should be able to use the snc name?

      Kind regards,

      Rainer

      Author's profile photo Stefan Schnell
      Stefan Schnell
      Blog Post Author

      Hello Rainer,

      unfortunately I have no experience with SSO.

      Cheers

      Stefan

      Author's profile photo Ziv Markovich
      Ziv Markovich

      Hi Stefan,

      Regarding error handling ,In case of errors  we get these popup windows , for example :
      is there any option to avoid the popup ?  in VBA on error command dose not dose help ,the popup is still displayed.

      Thanks
      Ziv

      Author's profile photo Stefan Schnell
      Stefan Schnell
      Blog Post Author

      Hello Ziv,

      thanks for your reply. It is very easy possible to redirect the error messages. Try the property ErrorMsgTarget and set it with 2. On this way you get the error messages in the info structure RFC_ERROR_INFO and you can get all details with the properties ErrorCode, ErrorGroup, ErrorKey, ErrorMessage etc. etc.

      Cheers
      Stefan