[Migrated content. Thread originally posted on 04 August 2011]
SI 2529598Client writes:
I want to define a COBOL class under .NET that allocates memory (via CBL_ALLOC_MEM) and passes the pointer to the allocated memory back to a c# calling routine.
I spoke to develoeprs and they were not sure if what was being done was the best approach, it was suggested that a Structure should be used to pass the data, below I am providing a sample (the developer provided this) for you to use/review:
You could use C# structs for example:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
using MicroFocus.COBOL.RuntimeServices;
namespace ConsoleApplication1
{
class Program
{
[Serializable]
[StructLayout(LayoutKind.Sequential)]
struct BCM
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
public byte[] ESeguib;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
public byte[] Nome;
public BCM(byte[] a, byte[] b)
{
this.ESeguib = a;
this.Nome = b;
}
public BCM(string a, string b)
{
this.ESeguib =
System.Text.Encoding.ASCII.GetBytes(string.Format("{0,-8}", a));
this.Nome =
System.Text.Encoding.ASCII.GetBytes(string.Format("{0,-8}", b));
}
public string ToString()
{
return System.Text.Encoding.ASCII.GetString(this.ESeguib)
System.Text.Encoding.ASCII.GetString(this.Nome);
}
}
static void Main(string[] args)
{
BCM x = new BCM("a", "bb");
byte[] xInBytes = RawSerialize(x);
RunUnit MyRunUnit = new RunUnit();
try
{
MyProgram prog = new MyProgram();
MyRunUnit.Add(prog);
MyRunUnit.Call("MyProgram", xInBytes);
x = (BCM)RawDeserialize(xInBytes, 0, typeof(BCM));
}
finally
{
if (MyRunUnit != null)
{
MyRunUnit.StopRun();
}
}
}
public static byte[] RawSerialize(object anything)
{
int rawSize = Marshal.SizeOf(anything);
IntPtr buffer = Marshal.AllocHGlobal(rawSize);
Marshal.StructureToPtr(anything, buffer, false);
byte[] rawDatas = new byte[rawSize];
Marshal.Copy(buffer, rawDatas, 0, rawSize);
Marshal.FreeHGlobal(buffer);
return rawDatas;
}
public static object RawDeserialize(byte[] rawData, int position,
Type anyType)
{
int rawsize = Marshal.SizeOf(anyType);
if (rawsize > rawData.Length)
return null;
IntPtr buffer = Marshal.AllocHGlobal(rawsize);
Marshal.Copy(rawData, position, buffer, rawsize);
object retobj = Marshal.PtrToStructure(buffer, anyType);
Marshal.FreeHGlobal(buffer);
return retobj;
}
}
}
and the COBOL being:
program-id. MyProgram.
linkage section.
01 BCM.
03 BCM-R.
05 BCM-PROGRAMMA.
07 BCM-ESEGUIB PIC X(8).
07 BCM-NOME PIC X(8).
procedure division using BCM.
move ALL "A" to BCM-ESEGUIB
move ALL "B" to BCM-NOME
call "xx" on exception
continue
goback.
--
The example provided still does not deal with the POINTER issue – as far as the Client can see. Client really needs an example of passing a pointer between C# (or just .NET ) and COBOL. The internet seems to be devoid of any examples but does suggest it is tricky.
Client thought for a while that he could keep the pointer as instance data but it is required by the C# program. Basically, the C# program calls the COBOL program to allocate memory. The memory pointer is passed back to C# and it (later on) “populates” data in a COBOL structure. The (copybook) structure contains a POINTER data type which is populated with the value passed to C#. So C# does not operate on the data referenced by the pointer but passes it to a different (legacy) COBOL program which does.
MemoryManager is trying to overlay a 4-byte structure, ptroverlay PIC X(4), and then pass this to a .NET data type, MemPointer binary-char unsigned occurs any, which occurs in LINKAGE. This
“set MemPointer to ptroverlay”
statement causes a Visual Studio internal error at runtime in the demo sent. Client assume it “works” at runtime because there is less checking.
Could anyone provide more information or a sample that would answer the question?