4

I am currently working on a at an IT company. They made their software using Clarion, and in that software they have a DLL which recalculates a lot of values from their database. I need to call this DLL from my C# project. I tried everything without it working.

My code is as below:

public partial class Form1 : Form
{
    [DllImport("EPNORM.dll", EntryPoint = "MyRecalcualate@FlOUcOUcOsbOUc")]
    public static extern void MyRecalcualate(System.Int64 myPtr, System.Int64 myLong, CWByte myByte);

    [DllImport("User32.dll")]
    public static extern Boolean MessageBeep(UInt32 beepType);

    public Form1()
    {
        InitializeComponent();
    }

    private void button1_Click(object sender, EventArgs e)
    {
        System.Int64 myPtrTemp = 1234;
        System.Int64 myLongTemp = 5678;
        System.Byte myByteTemp = 88;

        try
        {
            MyRecalcualate(myPtrTemp, myLongTemp, myByteTemp);
            bool messagebeep = MessageBeep(1);
        }
        catch (Exception ex)
        {
            MessageBox.Show(ex.Message);
        }
        finally
        {
            MessageBox.Show("Successful");
        }
    }
}

The problem is when I call it with breakpoints, it just disappears into the MyRecalcualate method and reaches the finallly block after 2 seconds and re-displays without doing anything from the DLL. Is this because there is something in the DLL method I need to fix or because I am doing the call wrong?

The parameters to the call below is : MyRecalculate(LONG, LONG, BYTE)

MyRecalcualate      PROCEDURE (MyStringPtr, MyLong, MyByte) ! Declare Procedure
LOC:CString         CSTRING(255)
LOC:Byte            BYTE
CODE
! clear completely LOC:CString with null values
LOC:CString = ALL('<0>', SIZE(LOC:CString))

! load string value, byte by byte, from memory address passed (MyStringPtr) and put into LOC:CString
I# = 0
LOOP
     PEEK(MyStringPtr + I# , LOC:Byte)
     IF LOC:Byte = 0 THEN BREAK END
     LOC:CString[I# + 1] = CHR(LOC:Byte)
     I# += 1
END

MESSAGE('MyString value is:||' & CLIP(LOC:CString))
MESSAGE('MyLong value is:||' & MyLong)
MESSAGE('MyByte value is :||' & MyByte)

This is the screenshot their contracted developer mailed me of the parameters and how he calls it in VB.NET: VB.NET CODE: http://imageshack.us/photo/my-images/269/callfromvisualbasictocl.jpg/ PARAMETERS IN CLARION: http://imageshack.us/photo/my-images/100/asdxg.jpg/

DanM7
  • 2,203
  • 3
  • 28
  • 46
  • Can you provide a bit more information on this Clarion library? It looks to me that there is a problem with the parameters you are passing. – Dimitris May 16 '12 at 11:54
  • hey dimitris i updated my post with the clarion side code – Mrlondon7100 May 16 '12 at 12:31
  • Do you have any example C/C++ that accesses these functions? – Peter Ritchie May 16 '12 at 12:38
  • Your call to Recalculate_Year_Norm requires 5 parameters where MyRecalculate takes 3. Why is that? – Dimitris May 16 '12 at 12:46
  • im sorry dimitris but i uploaded the wrong code, i edited it now(and thanks for trying to help me, i have been bugged by this for almost a week now searching everywhere online) – Mrlondon7100 May 16 '12 at 12:54
  • Hey Peter, i dont because the company i do this for made their entire app in Clarion :S and the real recalculate line is 500+ lines of code so they cba rewriting it as a stored procedure eg. – Mrlondon7100 May 16 '12 at 12:57
  • Ok I have noticed a couple of things. First of all in your entry point you have a spelling mistake "MyRecalcualate". Second your first parameter the string pointer is passed as an Int64 in C#. – Dimitris May 16 '12 at 13:01
  • hey again, i just talked with their argentinian programmer and he mailed me a picture of the parameters, its because the first parameter is a string parsed to a memory address, i uploaded a picture of both – Mrlondon7100 May 16 '12 at 15:37

1 Answers1

2

The first parameter is a pointer to a null-terminated character string. You can't just pass a random Int64 value. So your pinvoke should look like this:

[DllImport("EPNORM.dll", EntryPoint = "MyRecalcualate@FlOUcOUcOsbOUc")]
public static extern void MyRecalcualate(string myPtr, int myInt, byte myByte);

I believe that the second parameter, the Clarion LONG, is a 32 bit integer. So int on the C# side. What's more, you need to double check the calling convention on the Clarion side. Are you sure it is stdcall which is what your C# uses.

David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
  • hey i uploaded a picture of the parameters, its because the first parameter is a string value, but the parameter needs to be send like a long. so somehow they are encoding the string to a memory address and using that like parameter. – Mrlondon7100 May 16 '12 at 15:36
  • 1
    I'm sure you need to do it the way I say in my answer. My guess is that Clarion is 32 bit and that `LONG` is a 32 bit integer. That is the same size as a pointer on 32 bit. If all that is true then the second parameter needs to be typed as `int` rather than `long` in the P/invoke. – David Heffernan May 16 '12 at 15:55
  • As I just went through in [my most recent question here](http://stackoverflow.com/questions/13130365/convert-a-clarion-procedure-declaration-to-c-sharp-dllimport), Clarion `LONG` is a 32-bit signed integer, which maps to C# System.Int32 (`int`). – DanM7 Oct 31 '12 at 20:42
  • @Dan Thanks. I updated. Sounds like you've been having fun. Can't believe Clarion still exists. I remember using their TopSpeed Modula-2 back in the day!! – David Heffernan Oct 31 '12 at 20:55