我一直在尝试以下列方式调用在Delphi中创建的方法:
function _Func1(arrParams: array of TParams): Integer;stdcall;
type
TParams = record
Type: int;
Name: string;
Amount : Real;
end;
Run Code Online (Sandbox Code Playgroud)
我的代码是:
[DllImport("some.dll", EntryPoint = "_Func1", CallingConvention = CallingConvention.StdCall)]
public static extern int Func(
[MarshalAs(UnmanagedType.LPArray, ArraySubType=UnmanagedType.Struct)] TParams[] arrParams)
Run Code Online (Sandbox Code Playgroud)
结构是:
[StructLayoutAttribute(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct TParams
{
public int Type;
[MarshalAs(UnmanagedType.AnsiBStr)]
public string Name;
public double Amount;
}
Run Code Online (Sandbox Code Playgroud)
当我调用此方法时,我收到错误:无法编组"TParams"类型的字段"名称":无效的托管/非托管类型组合(字符串字段必须与LPStr,LPWStr,BStr或ByValTStr配对).
然而,这些组合都不起作用,因为Delphi的字符串以其长度为前缀并且肯定是Ansi(我已经尝试了其他字符串参数).有谁有线索如何解决这个问题?
这有两个主要问题,使用开放数组和使用Delphi string.
打开数组
Delphi开放数组是通过传递一个指向数组第一个元素的指针和一个指定最后一个项的索引的额外参数来实现的,high用Delphi术语表示.有关更多信息,请参阅此答案.
Delphi字符串
C#marshaller无法与Delphi字符串互操作.Delphi字符串是私有类型,仅在内部用于Delphi模块.相反,你应该使用以null结尾的字符串PAnsiChar.
把它们放在一起就可以这样写:
德尔福
type
TParams = record
_Type: Integer;//Type is a reserved word in Delphi
Name: PAnsiChar;
Amount: Double;
end;
function Func(const arrParams: array of TParams): Integer; stdcall;
Run Code Online (Sandbox Code Playgroud)
C#
[StructLayoutAttribute(LayoutKind.Sequential)]
public struct TParams
{
public int Type;
public string Name;
public double Amount;
}
[DllImport("some.dll")]
public static extern int Func(TParams[] arrParams, int high);
TParams[] params = new TParams[len];
...populate params
int retval = Func(params, params.Length-1);
Run Code Online (Sandbox Code Playgroud)