Как использовать C # для вызова функции, которая получает параметр открытого массива Delphi? - PullRequest
5 голосов
/ 30 октября 2011

Как мне преобразовать код Delphi в C #?Требуется array of Byte, но я не уверен, что такое эквивалент C #.Моя попытка не работает и выдает исключения, такие как 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);

Ответы [ 2 ]

8 голосов
/ 30 октября 2011

Открытый массив Delphi не является допустимым типом взаимодействия. Вы не можете легко сопоставить это с C # byte[] через P / invoke. В идеальном случае нативная DLL может открыть другой интерфейс, но, как вы заявили в комментариях, вы не можете контролировать этот интерфейс.

Тем не менее, вы можете обмануть код на C #, передав ему что-то, что Delphi DLL будет правильно интерпретировать, но это немного грязно. Ключ в том, что открытый массив Delphi, объявленный таким образом, имеет дополнительный неявный параметр, содержащий индекс последнего элемента в массиве.

[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);

Для ясности, несмотря на то, что списки параметров выглядят настолько разными, приведенный выше код C # успешно вызовет функцию DLL Delphi, объявленную так:

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

Я понятия не имею, подходит ли передача массива длиной 5 или вы действительно хотели просто установить для второго элемента ненулевое значение.

0 голосов
/ 13 декабря 2013

Так я реализовал успешную отправку массивов из и в 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
);

Обратите внимание, что отдельные типы имеют REF и массивы НЕ ИМЕЮТ REF , но массивы все равно будут работать как REF в любом случае

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;

Обратите внимание, что VAR являетсятакже с параметрами Array (аналог Delphi REF).

У меня были всевозможные ошибки, потому что я имел ref с массивами в коде C #

Еще одна проблема, которая вызвала у меня повреждение памятибыло то, что я не заметил, что эти коды не совпадают в Delphi и C #:

Delphi:

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

C #

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

То же самое в Delphi будетbe

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

Если вы переполните границы массивов, переданных в delphi, это также может вызвать всевозможные ошибки

...