Highlighted
Absent Member.
Absent Member.
3294 views

calling a .NET assembly

In the past I have integrated C & C++ routines with the AcuGT runtime by simply creating a DLL and calling the routines.  Now I need to integrate some C# .NET code.  Clearly it's a whole new world.

I have read the relevant parts of the manual and have had some help from MF tech support, but some questions remain.  

1. If my method returns an Int32, how is that accessible in the Cobol program?  Does RETURN-CODE reflect it?

2. The example program implies Cobol can pass a .NET System.String to a method (BTW it would be really helpful to see the .NET code that corresponds to this example).  Is this true - can I pass a Cobol string to a .NET method as a System.String object?  How exactly is that done?

3. Closely related question: How can the .NET method return a string?  If I pass a System.String per #2, could the .NET method modify and return it? (seems unlikely because a .NET System.String is immutable).

4. The main thing my methods need to do is parse and modify Cobol record buffers, containing a mix of strings, numeric values, COMP-3, COMP-4, etc. I am working on the assumption that these can't be passed as strings because they aren't strings.  Currently my C# routine is expecting an IntPtr, a pointer to a block of "unmanaged memory", that it will then move to a byte[] array and parse out.  I am hoping to use the same method to return such a block.  How would I code the Cobol to pass a record structure (FD) as an IntPtr ?  Or, is there a better way?

Many thanks for any insights into all of this.

Tags (1)
0 Likes
5 Replies
Highlighted
Absent Member.
Absent Member.

RE: calling a .NET assembly

I probably should have added: these are non-GUI.  No controls, no events.  Just 'subroutines' that accept some parameters, do useful (???) work, and return results.

0 Likes
Highlighted
Absent Member.
Absent Member.

RE: calling a .NET assembly

We use .NET calls to non-GUI as well, although I’ve never passed pointers to memory.

I’ve always had trouble with all the “COMP-?” types, so in my program I kept the fields passed simple. Strings, INTs, Double, etc., and before the DLL call I moved our data formats into working storage defined this way to be passed in. Looking at the documentation for the “USAGE” clause it seems pointer is a valid data type to pass.  

Also Pic X(size) defined COBOL fields seem to translate just fine to C# string types.

In my dll, I then moved the passed in values to whatever type I needed to work with on the C# side, did whatever work needed, and packed up all the returns values into a string separated by a delimiter of my choosing. Finally on the COBOL side, I unstring based on the delimiter, convert back to types we use in our software and move on.

FROM  DLL

namespace rm_cip

{

   public class cip_class

   {

       public static string Setup(double dAmount, string sUser, string sReference)

       {

         … work done …

         return sReturn;

       }

   }

}

FROM CBL

      SPECIAL-NAMES.    

          copy "rm_cip.def".            | output from running dll through NetDefGen.exe

       Working-Storage.

      77  CIP-Setup-Handle              usage handle of object.          

      77  return-string                 pic x(1024).

      01  Call-Fields.

          03  Call-Amount               double value 0.

          03  Call-User                 pic x(8).

          03  Call-Reference            pic x(40).

       Procedure Division.

          | values all come from rm_cip.def          

          create "rm_cip_dotnet35"

            namespace  is "rm_cip"

            class-name is "cip_class"

            constructor is constructor1()

            handle is CIP-Setup-Handle.      

          modify CIP-Setup-Handle "@Setup"

                         (call-amount,

                          call-user,

                          call-reference)

                   giving return-string.

          destroy CIP-Setup-Handle.  

And we’re done.

* edited for typo *

0 Likes
Highlighted
Absent Member.
Absent Member.

RE: calling a .NET assembly

cburlon7: Thank you!  You completely answered my string related question (#2 and #3), and by implication, question #1 - I can see how to access the return-code.  And it's very helpful to see the C# code assocated with the Cobol code.

I don't have the luxury of restructuring the data structures that are passed to the C# methods - the whole purpose of this project is to shift some data access from Cobol to C# and ADO.NET, and minimize the coding requirements on the Cobol side.  So I have to pass those ugly data structures with their COMP-3 & COMP-4 fields, and decode/encode them in C#.

I still don't quite have my head around passing an IntPtr to a cobol data structure.

0 Likes
Highlighted
Absent Member.
Absent Member.

RE: calling a .NET assembly

Forum people, I am quite stuck on this and I could really use some help.  I can pass my record buffer from Cobol to .NET as a string and that actually works... although it shouldn't, as the 'string' contains binary data.  But C# won't let me turn that process around: stuff binary data into a 'string' to return it to Cobol.

I think I really need a way to do one of the following:

1. Pass a pointer to a working-storage block.  Then my C# program can decode it, and change it, to return values.

OR

2. Pass my working-storage block as a byte array.

I cannot figure out a way to do either of these from the available documentation and samples, and I would greatly appreciate any pointers (no pun intended).

Please?

0 Likes
Highlighted
Absent Member.
Absent Member.

RE: calling a .NET assembly

I got this working.  The solution, for posterity:

Cobol - pass a pointer to a record buffer:

77 cobolsql-pointer USAGE POINTER.

SET cobolsql-pointer TO ADDRESS OF ws-bun-rec.

MODIFY cobolsql-handle "aaatest"(cobolsql-pointer, 768)

Compile using -Dw64 to the pointer is a 64-bit integer

C#:

public int aaatest(System.Int64 pnt, int length)

{

   byte[] bytes = new byte[length];

   IntPtr pointer = new IntPtr(pnt);

   Marshal.Copy(pointer, bytes, 0, length);

in other words, C# is receiving an Int64 not a pointer, and must convert it to a pointer.

0 Likes
The opinions expressed above are the personal opinions of the authors, not of Micro Focus. By using this site, you accept the Terms of Use and Rules of Participation. Certain versions of content ("Material") accessible here may contain branding from Hewlett-Packard Company (now HP Inc.) and Hewlett Packard Enterprise Company. As of September 1, 2017, the Material is now offered by Micro Focus, a separately owned and operated company. Any reference to the HP and Hewlett Packard Enterprise/HPE marks is historical in nature, and the HP and Hewlett Packard Enterprise/HPE marks are the property of their respective owners.