Как вызвать эту функцию в DLL Delphi из C # - PullRequest
4 голосов
/ 11 мая 2011

У меня есть эта функция, определенная в коде delphi:

procedure TestFLASHWNew(
    name: array of string; 
    ID: array of Integer;
    var d1:double
); stdcall;

Как я могу определить и вызвать ее из C #?

Ответы [ 2 ]

5 голосов
/ 12 мая 2011

Это немного грязный P / Invoke, потому что вы не можете (насколько я знаю, насколько я знаю) использовать любую из встроенных простых техник сортировки. Вместо этого вам нужно использовать Marshal.StructureToPtr вот так:

C #

[StructLayout(LayoutKind.Sequential)]
public struct MyItem
{
    [MarshalAs(UnmanagedType.LPWStr)]
    public string Name;
    public int ID;
}

[DllImport(@"mydll.dll")]
private static extern void TestFLASHWNewWrapper(IntPtr Items, int Count, ref double d1);

static void Main(string[] args)
{
    MyItem[] items = new MyItem[3];
    items[0].Name = "JFK";
    items[0].ID = 35;
    items[1].Name = "LBJ";
    items[1].ID = 36;
    items[2].Name = "Tricky Dicky";
    items[2].ID = 37;

    IntPtr itemsPtr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(MyItem))*items.Length);
    try
    {
        Int32 addr = itemsPtr.ToInt32();
        for (int i=0; i<items.Length; i++)
        {
            Marshal.StructureToPtr(items[i], new IntPtr(addr), false);
            addr += Marshal.SizeOf(typeof(MyItem));
        }

        double d1 = 666.0;
        TestFLASHWNewWrapper(itemsPtr, items.Length, ref d1);
        Console.WriteLine(d1);
    }
    finally
    {
        Marshal.FreeHGlobal(itemsPtr);
    }
}

Delphi

TItem = record
  Name: PChar;
  ID: Integer;
end;
PItem = ^TItem;

procedure TestFLASHWNewWrapper(Items: PItem; Count: Integer; var d1: Double); stdcall;
var
  i: Integer;
  name: array of string;
  ID: array of Integer;
begin
  SetLength(name, Count);
  SetLength(ID, Count);
  for i := 0 to Count-1 do begin
    name[i] := Items.Name;
    ID[i] := Items.ID
    inc(Items);
  end;
  TestFLASHWNew(name, ID, d1);
end;

Я реализовал это с помощью функции-оболочки, которая вызывает вашу функцию TestFLASHWNew, но вы, несомненно, захотите заново ее обработать.

Я предположил, что вы используете Delphi со строками Unicode. Если нет, то измените [MarshalAs(UnmanagedType.LPWStr)] на [MarshalAs(UnmanagedType.LPStr)].

2 голосов
/ 12 мая 2011

У функций Delphi есть две проблемы, которые должны вызываться не-Delphi кодом:

  • Он использует строки Delphi, которые являются проприетарной реализацией.
  • Он использует открытые массивы, которые также являются проприетарной реализацией.

Знание того, как реализованы открытые массивы и как настроен стек для их передачи, может позволить (это задокументировано) некоторые «хаки» на другой стороне, которые можно использовать для чтения этих параметров из стека. Со строками это немного сложнее, потому что их обработка сложнее.

Что вы могли бы сделать - если вы не можете изменить функцию - это определить более простую обертку вокруг этой функции, которая будет вызываться из C # (или любого другого языка), используя PChars вместо строк и явно передавая размеры массива .

...