Using Groups with .Net Com Controls Part 2

In part 1 I discussed mapping Clarion Groups to c# Structs specifically implementing MetaData from System.Runtime.InteropServices. I talked about the data types I have experimented with that have worked in passing data over to a .net com control.

In this article I will explain how to make the magic happen, and what results I have found.

The first bit of code you are going to need is a property to take an address of a group and convert that value into an interop pointer.

    private IntPtr groupPointer;
    public int GroupPointer {
        set {
            groupPointer = (IntPtr)value;
        }
    }

You can then pass the group to this property on the clarion side as follows:

 ?myOleControl{'GroupPointer'} = Address(TestGroup)

You only have to set this property once after the group has been instantiated.

The following code is then used to marshal the data into a TestStruct structure.

    private TestStruct testSrtuct;
    private TestStruct MarshalTestStruct() {
        try {
            return (TestStruct)Marshal.PtrToStructure(groupPointer, typeof(TestStruct));

        } catch {
            return new TestStruct();
        }
    }
    public void WorkOnTestGroup() {
          testStruct = MarshalTestStruct();
          // At this point testStruct will contain the values in the group.
    }

In clarion, you will set the values in the group to what you want to pass to .net then call

 ?myOleControl{'WorkOnTestGroup()'}

The method MarshalTestStruct uses PtrToStructure to marshal the data into testStruct.

From the call onwards you can write what ever code you need to access that data from the .net side. I personally am building a Collection of data passed from a clarion .tps file to .net, and have found stunning differences in speed as opposed to my previous method, which involved setting global properties on the .net side and then moving them field by field into a collection.

Over the same data set, I have found the speed to have gone from 1.25 Mins to just under 2 seconds to execute the loop over the code. Obviously hardware will make a difference.

The final bit of code I want to share is for if you want to the pass the structure back the other way.

This can be achieved with the following method

public SetStructToGroup() {
    //Code to change the struct would go here

    Marshal.StructureToPtr(testStruct, groupPointer, false); 
}

So a call from clarion as follows will then move current values from the structure to the clarion group.

 ?myOleControl{'SetStructToGroup()'}

This concludes my 2 part discussion on passing Clarion Groups to .Net.

Please leave any comments or questions you may have. I will try and answer them if I can.

3 Likes

This is great stuff @Mark_Sarson, thanks!

I was just playing around with this for DllExport instead of COM and it works great.
Essentially:

[DllExport]
public static void FillMyGroup(IntPtr groupPointer)
{
    TestStruct testStruct = (TestStruct)Marshal.PtrToStructure(groupPointer, typeof(TestStruct));
    testStruct.LongField = 1234;
    testStruct.StringField = "hi there!";
    Marshal.StructureToPtr(testStruct, groupPointer, false);
    return;
}

On the Clarion side I am using LoadLib and have a method in my class like this:

  MAP
    MODULE('MyNetExports.dll')
FillMyGroup         PROCEDURE(LONG pGroupAddress) ,NAME('FillMyGroup'),PASCAL,RAW,DLL(1)
    END
  END

MyClass.FillMyGroup         PROCEDURE(*GROUP pGroup)
  CODE
  FillMyGroup(Address(pGroup))

It probably makes more sense to use a named GROUP in the Clarion class method since it requires an agreement between the .NET code and the Clarion wrapper but the *GROUP works too. The labels on either side don’t matter of course, just the layouts must match.

3 Likes