开发者

how to call this function in a delphi dll from C#

开发者 https://www.devze.com 2023-03-04 23:32 出处:网络
I have this function defined in a d开发者_StackOverflowelphi code: procedure TestFLASHWNew( name: array of string;

I have this function defined in a d开发者_StackOverflowelphi code:

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

How can I define and call it from C#?


This is a bit of a messy P/Invoke because you can't (to the best of my admittedly limited knowledge) use any of the built-in easy marshalling techniques. Instead you need to use Marshal.StructureToPtr like this:

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;

I've implemented it with a wrapper function that calls your TestFLASHWNew function but you'll no doubt want to re-work it.

I've assumed you are using a Delphi with Unicode strings. If not then change [MarshalAs(UnmanagedType.LPWStr)] to [MarshalAs(UnmanagedType.LPStr)].


The Delphi functions has two issue to be called by non-Delphi code:

  • It uses Delphi strings, which are a proprietary implementation.
  • It uses open arrays, which again are a proprietary implementation.

Knowing how open arrays are implemented, and how the stack is setup to pass them could allow (it is documented) some "hacks" on the other side could be used to read that parameters from the stack. With strings it is a bit more difficult, because their handling is more complex.

What you could do - if you can't change the function - is to define some simpler wrapper around that function, that is callable from C# (or any other language), using PChars instead of strings and passing the array sizes explicitly.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号