calling cobol from .net c#, group parameters

[Migrated content. Thread originally posted on 19 January 2012]

I wan't to call a cobol program from c# and have two parameters which are defines as group elements.

Is there a way to call the cobol without writing a proxy program which then takes every single item into account?
I just wan't to give the cobol program a byte[] (sbyte[]) or a pointer to that array.

In java this is possible!

  • This can be done in Visual COBOL R4 using the SmartLinkage directive.

    Open up the Samples Browser under Start Menu->All Programs->Visual COBOL 2010->Visual COBOL Samples and then select the sample COBOL Book in the left column and C# WinBook in the right column and open this in Visual Studio 2010.

    Look at the properties on the LegacyBook project under the COBOL tab.
    The following Directives are set:

    ilsmartlinkage ilcutprefix(lnk-b-) ilcutprefix(lnk-)

    This tells the COBOL compiler to make the COBOL group items in the linkage section available to C# as individual elementary items with a .NET type so that C# can access the individual fields directly.

    Please see the documentation for this here:

  • This can be done in Visual COBOL R4 using the SmartLinkage directive.

    Open up the Samples Browser under Start Menu->All Programs->Visual COBOL 2010->Visual COBOL Samples and then select the sample COBOL Book in the left column and C# WinBook in the right column and open this in Visual Studio 2010.

    Look at the properties on the LegacyBook project under the COBOL tab.
    The following Directives are set:

    ilsmartlinkage ilcutprefix(lnk-b-) ilcutprefix(lnk-)

    This tells the COBOL compiler to make the COBOL group items in the linkage section available to C# as individual elementary items with a .NET type so that C# can access the individual fields directly.

    Please see the documentation for this here:

  • I see.

    I do not wan't to assign every single field in the structure.
    What I wan't is to assign the level 1 item only as the parameter.

    Is there a way to do that or can i wrap a C# byte[] or sbyte[] into a MF Reference?

    (In Java with the RuntimeSystem I can put a simple byte[] as parameter.)

  • Are you referring to calling a native COBOL .dll from C# or a managed COBOL .dll?
    Because you reference that you can do this in Java I will assume that it is referring to C# calling native COBOL.

    You can do this using a Platform/Invoke call from C# and passing the group item as a StringBuffer or using a C structure etc.

    The following is a simple example of C# calling a function named TESTCALL in a native COBOL .dll named cspinvoke.dll and having COBOL populate the group and return to C# where the fields are displayed.


        {
                StringBuilder sb = new StringBuilder(44);
                NativeCobol.TESTCALL(sb);
                txtName.Text = sb.ToString().Substring(0, 20);
                txtCompany.Text = sb.ToString().Substring(20, 20);
                txtAmount.Text =  sb.ToString().Substring(40, 4);
            }
        }
        public class NativeCobol
        {
            [DllImport("cspinvoke.dll", CharSet = CharSet.Ansi, CallingConvention=CallingConvention.Cdecl)]
            public static extern void TESTCALL(StringBuilder cobparams);
        }


    and the called COBOL:


           identification division.
           program-id. TESTCALL.
           data division.
           working-storage section.
           linkage section.
           01 group-item.
              05 g-name    pic x(20).
              05 g-company pic x(20).
              05 g-amount  pic 9(4).
           procedure division using group-item.

               move "C. Glazier" to g-name
               move "Micro Focus" to g-company
               move 1234 to g-amount
               goback.

  • Verified Answer

    You could use a valuetype/struct and marshall this to/from it to a byte[], this would then feel more natural in the C# side.

    For example here are some helper methods that will assist you in doing this:


        public T FromByteArray<T>(byte[] rawValue)
        {
            GCHandle handle = GCHandle.Alloc(rawValue, GCHandleType.Pinned);
            T structure = (T)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(T));
            handle.Free();
            return structure;
        }

        public byte[] ToByteArray(object value, int maxLength)
        {
            int rawsize = Marshal.SizeOf(value);
            byte[] rawdata = new byte[rawsize];
            GCHandle handle = GCHandle.Alloc(rawdata, GCHandleType.Pinned);
            Marshal.StructureToPtr(value, handle.AddrOfPinnedObject(),false);
            handle.Free();

            if (maxLength < rawdata.Length)
            {
                byte[] temp = new byte[maxLength];
                Array.Copy(rawdata, temp, maxLength);
                return temp;
            }
            else
            {
                return rawdata;
            }
        }