5

How do I convert the Delphi code into C#? It takes an array of Byte, but I'm not sure what the C# equivalent is. My attempt doesn't work and throws exceptions like AccessViolationException.

Delphi:

function SetLevel(a: array of byte): boolean; stdcall; external 'DMX510.dll';

C#:

[DllImport("DMX510.DLL")]
public static extern Boolean SetLevel(Byte[] bytearray);

Byte[] byteArray = new Byte[5];
byteArray[1] = 75;
SetLevel(byteArray);
Rob Kennedy
  • 161,384
  • 21
  • 275
  • 467
Pascal Bayer
  • 2,615
  • 8
  • 33
  • 51
  • http://www.monacor.de/fileadmin/user_upload/software_updates/DMX510dll.zip that's the link to the dll with some delphi sample code – Pascal Bayer Oct 30 '11 at 11:09
  • The DLL is used to control an USB-DMX controller. This controller allows me to instruct my lighting and laser hardware from my laptop. DMX ist a serial bus system and the array is used to output values between 0 to 255 to 510 hardware channels, each channel is for an individual device. The device is the byte array index and the value the DMX value. – Pascal Bayer Oct 30 '11 at 11:29
  • The source code and comments in the example show that there's a max of 510 channels. The byte array is prepared for that; it is given a length 510 when the form is created, and all bytes are initialized to 0. Now, I still don't know how to map a C# array to a Delphi array (if that is even possible this way), but I can imagine why an array of 5 will give you an access violation. – GolezTrol Oct 30 '11 at 11:32

2 Answers2

8

A Delphi open array is not a valid interop type. You can't easily match that up with a C# byte[] through a P/invoke. In an ideal world a different interface would be exposed by the native DLL but as you have stated in comments, you do not have control over that interface.

However, you can trick the C# code into passing something that the Delphi DLL will interpret correctly, but it's a little dirty. The key is that a Delphi open array declared like that has an extra implicit parameter containing the index of the last element in the array.

[DllImport(@"DMX510.DLL")]
public static extern bool SetLevel(byte[] byteArray, int high);

byte[] byteArray = new byte[] { 0, 75, 0, 0, 0};
SetLevel(byteArray, byteArray.Length-1);

To be clear, in spite of the parameter lists looking so different, the C# code above will successfully call the Delphi DLL function declared so:

function SetLevel(a: array of byte): boolean; stdcall;

I have no idea whether or not passing an array of length 5 is appropriate, or whether you really meant to just set the second item to a non-zero value.

David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
  • 1
    For what it's worth, you need to use this method when accessing arrays from libraries created in C++ into Delphi also. An alternative if you have access to the source code is to export your arrays using COM safe arrays. – S.Robins Oct 30 '11 at 13:37
0

This is the way how I implemented successfully sending arrays from and to Delphi & C#.

C#:

[DllImport("Vendors/DelphiCommunication.dll", CallingConvention = CallingConvention.StdCall)]
public static extern void LoadFromFileCHR(
    string sFileName,
    ref int iSize,
    ref double AreaCoef,
    ref double FWaveLength,
    ref bool FHasWaveLength,
    double[] ChromX,
    double[] ChromY
);

Note that single types have REF and arrays DO NOT HAVE REF, but arrays will still work like REF anyway

Delphi:

Type    
    ArrayDouble100k = array [0..99999] of Double;

procedure LoadFromFileCHR(
    FileName : String;
    var Size : Integer;
    var AreaCoef : Double;
    var FWaveLength: Double;
    var FHasWaveLength : Boolean;
    var ChromX : ArrayDouble100k;
    var ChromY : ArrayDouble100k); StdCall;
begin
   //...
end;

exports LoadFromFileCHR;

Note that VAR is also with Array parameters (Delphi analog of REF).

I had all sorts of errors, because I had ref with arrays in C# code

Another problem that caused memory corruption for me was that I did not notice that these codes are not the same in Delphi and C#:

Delphi:

for i := 0 to Length(fileCHR.ChromX) do //This is wrong

C#

for(int i = 0; i < fileCHR.ChromX.Length; i++)

The same in delphi would be

for i := 0 to Length(fileCHR.ChromX) - 1 do //This is right

If you overflow boundaries of arrays passed to delphi it could also cause all sorts of errors

Evalds Urtans
  • 6,436
  • 1
  • 41
  • 31