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.
精彩评论