Skip to main content

Demo of COBOL Using P/Invoke with CALL and C# style DLLImport

  • October 7, 2021
  • 0 replies
  • 0 views

Heather Caldwell

Environment

Visual COBOL for Visual Studio 2019 V7.0 Patch Update 1

Problem

How can I call a native .DLL written in COBOL or some other language from a managed .NET COBOL application?

Resolution

The attached zip file contains a Visual Studio solution with a native COBOL project called testpinvoke and a managed .NET COBOL project called ManClient.

Open the solution testpinvoke.sln in Visual Studio and Rebuild Solution. Both compiled executables will be output to the debug folder of the ManClient project. ManClient is set as the Startup project so you can start debugging through it using the F11 key or by selecting Step Into from the Debug menu item. 

This program will demonstrate calling a native COBOL .DLL using P/Invoke in two distinct ways. The first way uses a standard COBOL CALL statement and COBOL data types. The second way uses a C# style P/Invoke using the DLLImport attribute in order to create a method that can be invoked which will in turn call the native .DLL. The second method provides more control over the call-convention and parameter type information.

Additional Information

ManClient.cbl:

      $set ilusing"System.Runtime.InteropServices"
      $set ilpinvoke "bin\\x86\\debug\\testpinvoke.dll"
       program-id. ManClient as "ManClient.ManClient".

       data division.
       working-storage section.
       01 picXParam      pic x(10)       value "test".
       01 comp5Param     pic X(4) comp-5 value 123.
       01 stringParam    string          value "test".
       01 intParam       binary-long     value 123.
       01 ret-code       binary-long     value zeroes.
       01 any-key        pic x.
       01 pp procedure-pointer.
       procedure division.
           
           display "in managed client program"

           *> The following statement will call the NATIVEENT method within the native 
           *> COBOL .dll called testpinvoke.dll. The CALL statement can be used for calling
           *> simple native programs where the parameters are standard COBOL types.

           call "NATIVEENT" using picXParam comp5Param
                            returning ret-code

           display "return string  = " picXParam
           display "return integer = " comp5Param
           display "return-code    = " ret-code
           move zeroes to ret-code
           accept any-key


          *> The following statement will invoke the NATIVEENT method defined within the
          *> PInvokeClass below which in turn will call the entry point NATIVEENT within
          *> the native COBOL .dll called testpinvoke.dll.
          *>
          *> This uses the C# style of P/Invoke where attributes can be specified and
          *> parameters can be marshaled as specific types.
          *> This style of P/Invoke allows you to call native .dlls written in COBOL and
          *> other languages that may require different parameter passing functionality.
          *> This may also be easier to convert code from C# than converting C# code to
          *> COBOL CALL statements.

           set ret-code to type PInvokeClass::NATIVEENT(stringParam, intParam)

           display "return string  = " stringParam
           display "return integer = " intParam
           display "return-code    = " ret-code
           accept any-key.
           
           goback.

       end program ManClient.
       class-id PInvokeClass.
       
       method-id NATIVEENT static attribute DllImport("testpinvoke.dll", Property CallingConvention = type CallingConvention::Cdecl).
       procedure division
          using
             stringParam as string attribute MarshalAs(type UnmanagedType::VBByRefStr)
             intParam as binary-long attribute MarshalAs(type UnmanagedType::I4)
          returning ret-code as binary-long attribute MarshalAs(type UnmanagedType::I4).
                               .
        end method.
              
       end class.


testpinvoke.cbl:

      *> This program is compiled as a native .dll called
      *> testpinvoke.dll and it will be called using the C# style
      *> P/Invoke call within the ManClient program.
      *>
      *> Note that the program-id entry point is different than the
      *> name of the .dll so it must be defined that was in the
      *> calling program as well.
      *>---------------------------------------------------------------*
       identification division.
       program-id. testpinvoke.
       data division.
       working-storage section.
       01 ret-code       pic x(4) comp-5.
       linkage section.
       01 picxParam      pic x(10).
       01 intParam       pic x(4) comp-5.
       procedure division.

            goback.

       entry "nativeent" using picxParam intParam.
           move function upper-case(picxParam) to picxParam
           add 123 to intParam
           move 1 to ret-code
           goback returning ret-code.

https://portal.microfocus.com/s/article/KM000002023?language=en_US

#SupportTips/SupportTips/KnowledgeDocs
#SupportTips/KnowledgeDocs