3

I'm writing a C# .NET DLL for a Clarion (Clarion is C++ like programming language) program.

I call into the C# .NET DLL just fine, all is working great. However, I need that C# .NET DLL to receive a Clarion Procedure for callback purposes and then be able to call that procedure passing three int parameters.

The Clarion Procedure looks like this (a Clarion long is a C# int):

MyCallBack procedure(long p1, long p2, long p3)
... Data ...
    code
    ... Code ...

How do I pass the abvoe procedure to the C# .NET DLL and how does the C# .NET DLL call that procedure passing three int parameters?

Thanks in advance.

RFM
  • 93
  • 7

1 Answers1

3

Hopefully this example gives you somewhere to start, it is based on an example from the SoftVelocity newsgroups (cached plain text version here).

Note: I am using the RGiesecke DllExport package and a modified version of the Clarion LibMaker to create a compatible lib file. You mentioned that you are already calling into the C# DLL without issue so I am assuming that you are doing something similar. If you are interested, I go into this further on my blog.

Clarion Code

  PROGRAM
  MAP
    MODULE('ManagedCSharpDLL.dll')
CallbackProc                PROCEDURE(BSTRING PassedValue, *BSTRING ReturnValue),TYPE,PASCAL,DLL(TRUE)
SetCallback                 PROCEDURE(*CallbackProc pCallback),NAME('SetCallback'),PASCAL,RAW,DLL(TRUE)
TestCallback                PROCEDURE(*CString passedString),NAME('TestCallback'),PASCAL,RAW,DLL(TRUE)
    END
Callback                PROCEDURE(BSTRING PassedValue, *BSTRING ReturnValue),PASCAL
  END
a                   CSTRING(20)

CODE
  Message('Clarion: SetCallback(Callback)')
  SetCallback(Callback)

  a = 'Call Test Worked'
  Message('Clarion: Send message: ' & a)

  TestCallback(a)

  Message('Clarion: Made call and got back safely')

Callback      PROCEDURE(BSTRING PassedValue, *BSTRING ReturnValue)

  CODE
    MESSAGE('Clarion: Passed Value: ' & PassedValue)
    ReturnValue = 'Done'

C# Code

using System;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using RGiesecke.DllExport;

namespace ManagedCSharpDLL
{
  public static class UnmanagedExports
  {

    private static CallbackProc _callback;

    [DllExport("SetCallback", CallingConvention = System.Runtime.InteropServices.CallingConvention.StdCall)]
    public static void SetCallback(CallbackProc pCallback)
    {
      _callback = pCallback;
      MessageBox.Show("C#: SetCallback Completed");
    }

    [DllExport("TestCallback", CallingConvention = System.Runtime.InteropServices.CallingConvention.StdCall)]
    public static void TestCallback(string passedString)
    {
      string displayValue = passedString;
      string returnValue = String.Empty;

      MessageBox.Show("C#: About to call the Callback. displayValue=" + displayValue + ", returnValue=" + returnValue);
      _callback(displayValue, ref returnValue);
      MessageBox.Show("C#: Back from the Callback. displayValue=" + displayValue + ", returnValue=" + returnValue);
    }

    public delegate void CallbackProc( [MarshalAs(UnmanagedType.BStr)] String PassedValue,  [MarshalAs(UnmanagedType.BStr)] ref String ReturnValue);

  }
}
brahnp
  • 2,276
  • 1
  • 17
  • 22
  • I use RGiesecke DllExport package as well and had to modify the SoftVelocity provided LibMaker to get things working. I will give your code a try when I have time to test it. Thanks. – RFM Jul 18 '13 at 20:02
  • Great! I tend to use the LoadLibrary API now, once implemented it makes the workflow a lot less painful. I suppose you could adjust LibMaker to take command line parameters and automate it that way too. – brahnp Jul 21 '13 at 19:04
  • How do I get hold of the Modified libMaker? – spmoolman Oct 29 '19 at 13:41
  • Try over at [ClarionHub](https://clarionhub.com/t/some-help-with-c-interop/194/8?u=brahn) – brahnp Oct 31 '19 at 13:02