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.