Skip to main content

I'm trying to call my current classes (written in OO Cobol with NetX 4) from a new .net class which i have develop with NetX 5.1 but without changes in the old code. Now, in order to use COBOL Classes, i have create a COM Wrapper (build with Net4) which i call from the UI  (it's C#). Now i want to stop using that COM object and replace it with a .net proxy server. Is it possible? Could you help me with the coding? Thank you

Andy

I'm trying to call my current classes (written in OO Cobol with NetX 4) from a new .net class which i have develop with NetX 5.1 but without changes in the old code. Now, in order to use COBOL Classes, i have create a COM Wrapper (build with Net4) which i call from the UI  (it's C#). Now i want to stop using that COM object and replace it with a .net proxy server. Is it possible? Could you help me with the coding? Thank you

Andy

Can you please clarify what you mean by using a .NET Proxy Server instead of a COM wrapper?

What is a .NET Proxy Server?

Is it possible for you to recompile the native NX 4.0 OO classes using 5.1?

If it is going from .a NX 5.1 NET COBOL class to a NX 5.1 native COBOL class, it is not possible to invoke these native classes directly.

You could possibly do a platform invoke (CALL) to a native COBOL .dll that then calls the native OO classes and returns to .NET COBOL.

Is the C# UI out of the picture here or is that still a requirement also?

Thanks.


I'm trying to call my current classes (written in OO Cobol with NetX 4) from a new .net class which i have develop with NetX 5.1 but without changes in the old code. Now, in order to use COBOL Classes, i have create a COM Wrapper (build with Net4) which i call from the UI  (it's C#). Now i want to stop using that COM object and replace it with a .net proxy server. Is it possible? Could you help me with the coding? Thank you

Andy

"What is a .NET Proxy Server? "

Sorry. What i really want to say is that i need to write a .net cobol class in order to invoke native oo cobol methods. The same way that i do with the com object.

"Is it possible for you to recompile the native NX 4.0 OO classes using 5.1?"

i have done this already

"If it is going from .a NX 5.1 NET COBOL class to a NX 5.1 native COBOL class, it is not possible to invoke these native classes directly."

That was my plan :-(

"You could possibly do a platform invoke (CALL) to a native COBOL .dll that then calls the native OO classes and returns to .NET COBOL."

Ok. Could you help me with that? I have to tell you that isn't one dll. I use inheritance and there are more than one classes.

"Is the C# UI out of the picture here or is that still a requirement also?"

The C# is the UI. If i get .net cobol anf native cobol work together then the UI is not a problem. I think....


I'm trying to call my current classes (written in OO Cobol with NetX 4) from a new .net class which i have develop with NetX 5.1 but without changes in the old code. Now, in order to use COBOL Classes, i have create a COM Wrapper (build with Net4) which i call from the UI  (it's C#). Now i want to stop using that COM object and replace it with a .net proxy server. Is it possible? Could you help me with the coding? Thank you

Andy

"What is a .NET Proxy Server? "

Sorry. What i really want to say is that i need to write a .net cobol class in order to invoke native oo cobol methods. The same way that i do with the com object.

"Is it possible for you to recompile the native NX 4.0 OO classes using 5.1?"

i have done this already

"If it is going from .a NX 5.1 NET COBOL class to a NX 5.1 native COBOL class, it is not possible to invoke these native classes directly."

That was my plan :-(

"You could possibly do a platform invoke (CALL) to a native COBOL .dll that then calls the native OO classes and returns to .NET COBOL."

Ok. Could you help me with that? I have to tell you that isn't one dll. I use inheritance and there are more than one classes.

"Is the C# UI out of the picture here or is that still a requirement also?"

The C# is the UI. If i get .net cobol anf native cobol work together then the UI is not a problem. I think....


I'm trying to call my current classes (written in OO Cobol with NetX 4) from a new .net class which i have develop with NetX 5.1 but without changes in the old code. Now, in order to use COBOL Classes, i have create a COM Wrapper (build with Net4) which i call from the UI  (it's C#). Now i want to stop using that COM object and replace it with a .net proxy server. Is it possible? Could you help me with the coding? Thank you

Andy

You would have to create a .DLL in Net Express that could be called by the .NET COBOL class.

You could call it by its main entry point or an alternate entry point and pass parameters using the standard COBOL CALL statement.
All of the underlying complexities are handled by the compiler and run-time system, so all you have to do is a standard COBOL CALL.

I just tested this here by creating a native 32-bit .DLL in Net Express in which I copied the source from one of our example OO programs called COLL0. I created a Windows Forms application in Net Express .Net (VS 2008) that, when a button is pressed will call the native program using a CALL statement.

It also passed a parameter of PIC X(20).

The native .DLL will populate the parameter with a string value and will then invoke a number of classes in the NX Class Library.
It then returns via GOBACK statement.

When control returns to the .Net program it will set a textbox to the value of the returned parameter set in the native .DLL.

You will either have to copy the native .DLL into the same folder as the .calling .Net .EXE or add a reference to the .DLL into the managed app project.

The programs look like the following:

nativeclass.cbl:

     $set mfoo
      id division.
      program-id.   nativeclass.
     *-------------------------------------------------------------
     * Program to create five different types of collection and
     * initialize with intrinsic values.
     *-------------------------------------------------------------
     * Copyright (C) 1996-2000  Micro Focus International Ltd.
     * All Rights Reserved.
     *-------------------------------------------------------------
      class-control.
          OrderedCollection is class "ordrdcll"
          Array is class "array"
          Bag is class "bag"
          SortedCollection is class "srtdclln"
          CharacterArray is class "chararry"
          ValueSet is class "valueset"
          .
      working-storage section.
     *----Data for initializing the collections
          01  loopCount               pic x(4) comp-5.
          01  element                 pic x(4) comp-5.
          01  element2                pic x(4) comp-5.
          01  i                       pic x(4) comp-5.
     *----Boolean variable to receive results from some collection
     *    methods.
          01  trueOrFalse             pic x comp-5.
              88  isTrue              value 1.
              88  isFalse             value 0.
     *----Object references to hold collection instances and
     *    a class template for COBOL intrinsic data.
          01  aBag                    object reference.
          01  anArray                 object reference.
          01  anOrderedCollection     object reference.
          01  aSortedCollection       object reference.
          01  aString                 object reference.
          01  aValueSet               object reference.
          01  fruitdata.
              03  filler pic x(20) value "Mango".
              03  filler pic x(20) value "Apple".
              03  filler pic x(20) value "Pear".
              03  filler pic x(20) value "Banana".
              03  filler pic x(20) value "Apricot".
              03  filler pic x(20) value "Strawberry".
              03  filler pic x(20) value "Kiwifruit".
              03  filler pic x(20) value "Grape".
              03  filler pic x(20) value "Lemon".
              03  filler pic x(20) value "Orange".
          01  collectionData          pic x(20)
                                      occurs 10 times
                                      redefines fruitData.
      linkage section.
      01 myparams    pic x(20).
      procedure division using myparams.
          move "from nativeclass" to myparams
     *----A001. Create an array of 10 elements.
          move 10 to i
          invoke Array "ofReferences" using i
                              returning anArray
     *----A002. Create an ordered collection.
          invoke OrderedCollection "ofReferences"
                                   using i
                               returning anOrderedCollection
     *----A003. Create a sorted collection
          invoke SortedCollection "ofReferences" using i
                                         returning aSortedCollection
     *----A004. Create a bag.
          invoke Bag "ofreferences" using i
                                returning aBag
     *----A005. Create a ValueSet.
          invoke ValueSet "ofReferences" using i
                                     returning aValueSet
     *----A006. Store CharacterArray instances for the strings declared
     *          in working storage.
          move 20 to i
          perform varying loopCount from 1 by 1
                                    until loopCount > 10
     *--------A007. Create a CharacterArray for each of the data items
     *        in the table. CharacterArrays are used for holding and
     *        manipulating strings.
              invoke CharacterArray "withByteLengthValue"
                     using i collectionData(loopCount)
                 returning aString
     *--------A008. Store the string in each collection.
              invoke aValueSet "add" using aString
                                 returning aString
              invoke aBag "add" using aString
                            returning aString
              invoke anArray "atPut" using loopcount aString
                                 returning aString
     *--------A009. Although the OrderedCollection and SortedCollection
     *              are indexed, when these collections are empty you
     *              have to "add" the new elements.
              invoke anOrderedCollection "add" using aString
                                           returning aString
              invoke aSortedCollection "add" using aString
                                         returning aString
          end-perform
     *----A010. Get the fourth element from the Array and display it.
          move 4 to loopCount
          invoke anArray "at" using loopCount
                          returning aString
          invoke aString "display"
          display " "
     *----A011. Bags are not indexed, so ask the bag if it includes an
     *    element with the value of aString. You query a ValueSet in
     *    the same way.
          invoke aBag "includes" using aString
                             returning trueOrFalse
          if isTrue
              display  "Bag contains " with no advancing
              invoke aString "display"
          else
              display  "Bag does not contain " with no advancing
              invoke aString "display"
          end-if
          display " "
     *----A012. Bags (unlike ValueSets) allow duplicates. You can
     *          add a second occurrence of the element.
          invoke aBag "add" using aString
                        returning aString
     *----A013. You can ask a bag how many occurrences it
     *    contains of a particular element.
          invoke aBag "occurrencesOf" using aString
                                  returning i
          display "Bag contains " i " occurrences of "
                  with no advancing
          invoke aString "display"
          display " "
     *----A014. You can ask any type of collection how many occurrences
     *    it has of a particular element.
          invoke anArray "occurrencesOf" using aString returning i
          display "Array contains " i " occurrences of "
                  with no advancing
          invoke aString "display"
          display " "
     *----A015. The next statement adds a second occurrence of aString
     *           to the ValueSet. ValueSets do not maintain duplicates,
     *           so when we query the ValueSet it will still return 1.
          invoke aValueSet "add" using aString
                             returning aString
          invoke aValueSet "occurrencesOf" using aString returning i
          display "ValueSet contains " i " occurrences of "
                  with no advancing
          invoke aString "display"
          display " "
     *----A016. Display the entire contents of the sorted and ordered
     *    collections, to show the different order of aStrings.
          display "Collection contents"
          display "Ordered:            Sorted:"
          perform varying loopCount from 1 by 1 until loopCount > 10
              invoke anOrderedCollection "at" using loopCount
                                          returning aString
              invoke aString "display"
              invoke aSortedCollection "at" using loopcount
                                        returning aString
              invoke aString "display"
              display " "
          end-perform
          goback.

managed class callnativeclass.cbl

      class-id. Form1 as "callnativeclass.Form1" is partial
                inherits type "System.Windows.Forms.Form".
      environment division.
      configuration section.
      repository.
      object.
      working-storage section.
      method-id. NEW.
      procedure division.
          invoke self::"InitializeComponent"
          goback.
      end method NEW.
      method-id.  "button1_Click" final private.
      01 myparams   pic x(20).
      procedure division using by value sender as object e as type "System.EventArgs".
        move "from managed" to myparams
        call "NATIVECLASS" using myparams
        set self::"textBox1"::"Text" to myparams
      end method "button1_Click".
      end object.
      end class Form1.


I'm trying to call my current classes (written in OO Cobol with NetX 4) from a new .net class which i have develop with NetX 5.1 but without changes in the old code. Now, in order to use COBOL Classes, i have create a COM Wrapper (build with Net4) which i call from the UI  (it's C#). Now i want to stop using that COM object and replace it with a .net proxy server. Is it possible? Could you help me with the coding? Thank you

Andy

Hi Chris,

thank you very much for your help but  this is not what i'm looking for. The application that i'm trying to migrate to the .NET framework is too big and new extensive coding is not an option . As i understand i can't invoke native classes directly from managed code. I think that my next option is to transform my  native classes into .NET  Cobol classes. I'm giving you  an example of three classes which are representative of the original native classes. The key is that we use inheritance with data. I will be obliged if you could send me the equivalent code in .NET COBOL because i try it myself and after many attempts i failed to build the project.

Thank you in advance for your time and for your help,

Andy

 

Class1   

   class-id. LifeProc data is protected

                inherits from base.

      object section.

      class-control.

          LifeProc is class "lifeproc"

          base is class "base"

          .

     *>-----------------------------------------------------------

      working-storage section. *> Definition of global data

     *>-----------------------------------------------------------

      01 file-st                  pic xx.

     *>-----------------------------------------------------------

      class-object.   *> Definition of class data and methods

     *>-----------------------------------------------------------

      object-storage section.

      end class-object.

     *>-----------------------------------------------------------

      object.         *> Definition of instance data and methods

     *>-----------------------------------------------------------

      object-storage section.

      EXEC SQL INCLUDE SQLCA END-EXEC.

          exec sql

              declare ccurs  cursor for csql

              for read only

          end-exec.

         01 afield pic s9(5) comp-3.

.

etc

Class2

     $set constant ifeuro "true"

     $set ooctrl( p)

     *>-----------------------------------------------------------

     *> Class description

     *>-----------------------------------------------------------

      class-id. lifepolext data is protected

                inherits from LIFEPROC with data.

      object section.

      class-control.

          lifepolext is class "lifepolext"

     *> OCWIZARD - start list of classes

          LIFEPROC is class "lifeproc"

     *> OCWIZARD - end list of classes

     *>---USER-CODE. Add any additional class names below.

          .

     *>-----------------------------------------------------------

      working-storage section. *> Definition of global data

     *>-----------------------------------------------------------

     *>-----------------------------------------------------------

      class-object.   *> Definition of class data and methods

     *>-----------------------------------------------------------

      object-storage section.

     *> OCWIZARD - start standard class methods

     *> OCWIZARD - end standard class methods

      end class-object.

     *>-----------------------------------------------------------

      object.         *> Definition of instance data and methods

     *>-----------------------------------------------------------

      object-storage section.

          EXEC SQL

               declare queuepolcur readonly cursor for queuepolsql

          END-EXEC.

          EXEC SQL

               declare mergecur readonly cursor for mergesql

          END-EXEC.

          exec sql

              declare bebcurcd cursor for bebsql

          end-exec

          exec sql

              declare ccurs readonly cursor for csql

          end-exec.

      78 lifexmlprogram value "lifexmlprocess".

      01 command-count    pic 9(10).

      01 achcount    pic 9(10).

      01 queue-command     pic x(20000).

      01 eltaflag         pic s9(1) comp-3.

      01 doseisdeathflag  pic s9(1) comp-3.

      01 polnuml      pic s9(10) comp-3.

Class3

      $set constant ifeuro "true"
      $set ooctrl( p)
      
      *>-----------------------------------------------------------
      *> Class description
      *>-----------------------------------------------------------
       class-id. lifepol data is protected
                 inherits from LIFEPOLEX with data.

       object section.
       class-control.
           lifepol is class "lifepol"
      *> OCWIZARD - start list of classes

           LIFEPOLEX is class "lifepolex"
      *> OCWIZARD - end list of classes
      *>---USER-CODE. Add any additional class names below.

           .

      *>-----------------------------------------------------------
       working-storage section. *> Definition of global data
      *>-----------------------------------------------------------

      *>-----------------------------------------------------------
       class-object.   *> Definition of class data and methods
      *>-----------------------------------------------------------
       object-storage section.

      *> OCWIZARD - start standard class methods
      *> OCWIZARD - end standard class methods

       end class-object.

      *>-----------------------------------------------------------
       object.         *> Definition of instance data and methods
      *>-----------------------------------------------------------
       object-storage section.

      *if testcode = "yes"
      *78 lifexmlprogram value "lifexmlprocessuat".
      *else
       78 lifexmlprogram value "lifexmlprocess".
      *end


           EXEC SQL
                declare mathcur cursor for mathsql
               for read only
           END-EXEC.


I'm trying to call my current classes (written in OO Cobol with NetX 4) from a new .net class which i have develop with NetX 5.1 but without changes in the old code. Now, in order to use COBOL Classes, i have create a COM Wrapper (build with Net4) which i call from the UI  (it's C#). Now i want to stop using that COM object and replace it with a .net proxy server. Is it possible? Could you help me with the coding? Thank you

Andy

If your ultimate goal is to avoid making extensive changes to your existing source then converting your current native OO source to managed .NET source may not be the best route for you.

The inheritance of data is supported but not in the same manner as in native OO, i.e., the INHERITS WITH DATA clause is not supported.

Instead data items to be inherited must be defined as PROTECTED and then they can be accessed in the sub-classes by using the syntax self::data-item.

This is currently only supported for .NET data types and will not work with COBOL types like PIC X or PIC 9, etc.

There are other differences also.

The Net Express OO classes like Base, GUI and OLE are not supported in managed code.
Managed code classes do not inherit from the Base class but instead are derived from the .Net Object class.

Also .Net managed code is a strongly typed language so all of your object references must specifiy a type.

You cannot do:

01 my-object    object reference.

   invoke myclass "new" returning my-object

You instead must specify what type my-object will hold.

01 my-object   object reference myclass.

Visual COBOL actually supports a new OO syntax which is much easier to use than the .NET syntax provided by Net Express. You no longer need to define all of your classes in a repository but instead can reference the classes directly using the type keyword.

What is the ultimate goal here that you are trying to achieve?

You state that you had a COM wrapper that accessed these native classes before.
Why is this no longer suitable to you?

I can understand why you would want all of your code in .NET, I just want to make you aware that this is not just a simple recompile of your native OO application. It will most likely be a major undertaking.

As for the example you asked for, the following code compiles fine in Visual COBOL and I have added a couple of methods to show you how data inheritance works.

Be aware though that there does seem to be a problem with the NX 5.1 compiler in that the data inheritance is currently not working correctly. We are looking into this now.

     $set sql(dbman=ado)
     $set constant ifeuro "true"
      class-id. LifeProc.
      environment division.
      configuration section.
      repository.
         class clsLifeProc as "LifeProc".
      static.
      working-storage section.
      01 file-st    pic xx.
      end static.
      object.
      working-storage section.
      exec sql include SQLCA end-exec.
      exec sql declare ccurs cursor for csql
         for read only
      end-exec
      01 afield   binary-long protected.
      end object.
      end class LifeProc.

      class-id. lifepolext inherits from clsLifeProc.
      environment division.
      configuration section.
      repository.
         class clsLifeProc as "LifeProc"
         class clslifepolext as "lifepolext"
         .
      static.
      working-storage section.
      end static.
      object.
      working-storage section.
      exec sql
         declare queuepolcur readonly cursor for queuepolsql
      end-exec.
      exec sql
         declare bebcurcd cursor for mergesql for read only
      end-exec
      exec sql
         declare ccurs readonly cursor for csql
      end-exec
      78 lifexmlprogram value "lifexmlprocess".
      01 command-count  pic 9(10).
      01 achcount       pic 9(10).
      01 queue-command  pic x(20000).
      01 eltaflag       pic s9(1) comp-3.
      01 doseisdeathflag pic s9(1) comp-3.
      01 polnuml        pic s9(10) comp-3.
      method-id. "testdata".
      procedure division.
         move 99 to self::afield
      end method "testdata".          
      end object.
      end class lifepolext.

      class-id. lifepol inherits from clslifepolext.
      environment division.
      configuration section.
      repository.
         class clslifepol as "lifepol"
         class clslifepolext as "lifepolext".
      static.
      working-storage section.
      end static.
      object.
      working-storage section.Z
      78 lifexmlprogram  value "lifexmlprocess".
      exec sql
         declare mathcur cursor for mathsql for read only
      end-exec.
      method-id.  "newtest".
      procedure division.
         move 10 to self::afield
      end method "newtest".      
      end object.
      end class lifepol.

The above code is used in Net Express .NET but will compile in Visual COBOL also.

The more streamlined syntax supported in Visual COBOL for the same classes would be:

     $set sql(dbman=ado)
     $set constant ifeuro "true"
       class-id. LifeProc.
       working-storage section.
       01 file-st    pic xx static.
       exec sql include SQLCA end-exec.
       exec sql 
             declare ccurs cursor for csql for read only
       end-exec
       01 afield   binary-long protected.
       end class LifeProc.
     
       class-id. lifepolext inherits from type LifeProc.
       working-storage section.
       exec sql
           declare queuepolcur readonly cursor for queuepolsql
       end-exec.
       exec sql
          declare bebcurcd cursor for mergesql for read only
       end-exec      
       exec sql
          declare ccurs readonly cursor for csql
       end-exec
       78 lifexmlprogram value "lifexmlprocess".
       01 command-count  pic 9(10).      
       01 achcount       pic 9(10).      
       01 queue-command  pic x(20000).      
       01 eltaflag       pic s9(1) comp-3.      
       01 doseisdeathflag pic s9(1) comp-3.      
       01 polnuml        pic s9(10) comp-3.      
       method-id testdata.
       procedure division.
            move 99 to self::afield
       end method.
       end class lifepolext.

       class-id. lifepol inherits from type lifepolext.
       working-storage section.
       78 lifexmlprogram  value "lifexmlprocess".
       exec sql
          declare mathcur cursor for mathsql for read only
       end-exec.
       method-id newtest.
       procedure division.
            move 10 to self::afield      
       end method.
       end class lifepol.

 


I'm trying to call my current classes (written in OO Cobol with NetX 4) from a new .net class which i have develop with NetX 5.1 but without changes in the old code. Now, in order to use COBOL Classes, i have create a COM Wrapper (build with Net4) which i call from the UI  (it's C#). Now i want to stop using that COM object and replace it with a .net proxy server. Is it possible? Could you help me with the coding? Thank you

Andy

I'm a little dissapointed from your answer. I'm using Microfocus Cobol since 1987 and i have migrate many times application to variety of platforms. I started with character based ( from DOS to UNIX) and after that i moved to grafical env. like Windows NT and finally the last 15 years i use OO Cobol. And your products were always ready to support any decision and risks that i have take over the years. I understand that moving to .NET is something different but i was convinced that the transformation gonna be easy since i have already a OO source. But that's life.

To answer your querstions:

My main goal is to move the application to the new technology and start using that technology. I want to be able to create/or consume WCF Services, build a new modern UI etc. But reusing the (huge) existing code which is tested and works fine translated in the new platform. I feel very weird every time that i have to say that i can't consume a WCF service from the application ......  

Now we have people to create WCF Services in C# and they use the COM object. But the management feels that COM objects are obsolete like COBOL....Any suggestions?


I'm trying to call my current classes (written in OO Cobol with NetX 4) from a new .net class which i have develop with NetX 5.1 but without changes in the old code. Now, in order to use COBOL Classes, i have create a COM Wrapper (build with Net4) which i call from the UI  (it's C#). Now i want to stop using that COM object and replace it with a .net proxy server. Is it possible? Could you help me with the coding? Thank you

Andy

I didn't mean to imply that it would be impossible to convert your native OO application to managed .NET code, It could certainly be done but the amount of work required really depends on what your application is doing. If you are making heavy use of the Net Express class libraries and use a lot of untyped object references then it would be a lot of work.

If the conversion effort was too great the only other options that I have for you are to either keep the COM wrapper like you have been using or to create a WCF Service in COBOL and use P/Invoke to call the native OO code.

After discussing this with Development I think that keeping the COM wrapper might be the best approach after all.

I ran the WCF-->P/Invoke by Development and they had the following to say:

"Yes, it is possible but as the native COBOL does not know anything about managed RunUnit’s, the native code will need to be stateless for it to work well.  

Also, using WCF and platform invokes may well be unacceptable to the administrator as it requires higher permissions than the use of COM does…. And it comes with a greater risk factor..  The COM support can run out of process, so if anything went wrong , it would not cause the WCF server to become unavailable.

I personally would not recommend using pinvoke and WCF, COM might not be trendy but it can be managed/run out of process/recycled etc.."

It might also be worth saying that COM has not died in the eyes of Microsoft… as the Metro support in Windows 8 is based around it… although it is more sophisticated COM at the heart of it..

If anybody else has ideas or comments on this subject please feel free to post them here.

Thanks.