[Last Call] Learn how to a build a cloud-first strategyRegister Now

x
  • Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 718
  • Last Modified:

using Delphi DLL in C#

I want to use a delphi DLL in my C# program, but am having a problem.
Delphi function prototype (LongInt has size od 4 bytes in Delphi):

FUNCTION _Status_Cmd(    PortIndex  : LongInt;
                                 DevAddr    : LongInt;
                             VAR Data       : ARRAY OF LongInt): LongInt;       STDCALL;


Then, in my C program, I have:

[DllImport("comcom32.dll", ExactSpelling=false, SetLastError=true)]
private static extern int _Status_Cmd(int PortIndex, int DevAddr, int[] Data);

...


int[] iData = new int[100]; (in delphi example, iData is set to 100 zero elements, too)
int PortIndex = 1, ret;

ret = _Status_Cmd(PortIndex, 0, iData);

After return, data should be like this:

5 0 32 132 142 0 0 0 0 .......

as is the case, if I use this function in Delphi, but if I use the function in my C# program, I get this:

5 0 0 0 0 0 0 0 0 ........ (all zeroes, except first element in int array)

So, only the first element is set correctly, others are left alone. I tried with various marshalling functions, but with no success so far.

All suggestions appreciated.
0
Sagadin
Asked:
Sagadin
  • 5
  • 2
  • 2
1 Solution
 
testnCommented:
Try

[DllImport("comcom32.dll", ExactSpelling=false, SetLastError=true)]
private static extern int _Status_Cmd(int PortIndex, int DevAddr, [MarshalAs(UnmanagedType.LPArray, SizeConst=100)] int[] Data);
0
 
SagadinAuthor Commented:
Thank you for your quick response. Yes, I have tried this MarshalAs function before, now again, but it doesn't work. Still the same problem. :(
0
 
testnCommented:
how about?

[DllImport("comcom32.dll", ExactSpelling=false, SetLastError=true)]
private static extern int _Status_Cmd(int PortIndex, int DevAddr, [MarshalAs(UnmanagedType.LPArray, SizeConst=100)] [in,out] int[] Data);

0
What does it mean to be "Always On"?

Is your cloud always on? With an Always On cloud you won't have to worry about downtime for maintenance or software application code updates, ensuring that your bottom line isn't affected.

 
SagadinAuthor Commented:
don't know if I understand you correctly.

If I use:

private static extern int _Status_Cmd(int PortIndex, int DevAddr, [MarshalAs(UnmanagedType.LPArray, SizeConst=100)] in int[] Data);

I get compiler error (Type expected). If I use:

private static extern int _Status_Cmd(int PortIndex, int DevAddr, [MarshalAs(UnmanagedType.LPArray, SizeConst=100)] out int[] Data);

it compiles fine, but when program is run, an exception occurs:

----
An unhandled exception of type 'System.Runtime.InteropServices.MarshalDirectiveException' occurred in test.exe

Additional information: Can not use SizeParamIndex for byref array parameters.
---

So I deleted the ...SizeConst=100... part, this time program gives me the exception:

---
An unhandled exception of type 'System.NullReferenceException' occurred in test.exe

Additional information: Object reference not set to an instance of an object.
---
0
 
SagadinAuthor Commented:
Oh, now I tried:

[DllImport("comcom32.dll", ExactSpelling=false, SetLastError=true)]
private static extern int _Status_Cmd(int PortIndex, int DevAddr, [MarshalAs(UnmanagedType.LPArray, SizeConst=100)] [In,Out] int[] Data);

But still the same. Even tried [In] [Out] and [Out,In], result always the same, only first int is set.
0
 
ptmcompCommented:
How about this:

[DllImport("comcom32.dll", ExactSpelling=false, SetLastError=true)]
private static extern int _Status_Cmd(int PortIndex, int DevAddr, IntPtr addrIntArray);


IntPtr addrIntArray;

addrIntArray = Marshal.AllocHGlobal(100*4); // 100 * sizeof(Int32)
int ret = _Status_Cmd(portIndex, devAddr, ref addrIntArray); // try also without ref

Int32[] result = new Int32[100];
Marshal.Copy(addrIntArray, result, 0, 100);

0
 
SagadinAuthor Commented:
I'm afraid still no success, now the "result" array looks like this:

5  782282168 78299680 78301820 78301956 ......

So again, only the first int is OK. Any other ideas? I ran out of mine... :(
0
 
ptmcompCommented:
How about:

IntPtr addrIntArray;

Int32[] result = new Int32[100];
addrIntArray = Marshal.AllocHGlobal(100*4); // 100 * sizeof(Int32)
Marshal.Copy(result, 0, addrIntArray, 100);
int ret = _Status_Cmd(portIndex, devAddr, addrIntArray); // try also with ref
Marshal.Copy(addrIntArray, result, 0, 100);
0
 
SagadinAuthor Commented:
Thank you both for help. The problem was in DLL, delphi prototype has only three fields defined and it works fine when compiled with Delphi. Now I got a C++ .h file and in it has also an additional function argument which is obviously needed when library is used with C# or C++:

_Status_Cmd(portIndex, devAddr, addrIntArray, 100);

So, I've been calling it with one actual argument too little. Works for Delphi, but not for C#.
0

Featured Post

Concerto Cloud for Software Providers & ISVs

Can Concerto Cloud Services help you focus on evolving your application offerings, while delivering the best cloud experience to your customers? From DevOps to revenue models and customer support, the answer is yes!

Learn how Concerto can help you.

  • 5
  • 2
  • 2
Tackle projects and never again get stuck behind a technical roadblock.
Join Now