我想调用的方法德尔福DLL具有以下特征:
function SMap4Ovr(const OverFileName : ShortString ;
const Aclay : Integer ;
const Acarbon : Double ;
out errstr : ShortString): WordBool;
我正在使用C#以下导入:
[DllImport("SMap.dll", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Ansi)]
public static extern bool SMap4Ovr(
string OverFileName,
int Aclay,
double Acarbon,
out string errstr
);
但是,我得到一个AccessViolationException。
我似乎能够调入一对夫妇在具有字符串参数,而不是整数或双打的DLL简单的方法。
我也试图与CallingConvention = CallingConvention.Cdecl但是这给了我同样的错误。
在编写代码的互操作至关重要的是在各个方面的接口匹配的两侧。 这里的主要问题是,你必须同意双方:
- 调用约定。
- 参数列表。
- 参数类型和语义。
第一个发现是,你调用约定不匹配。 你必须register
在德尔福侧和stdcall
在C#的一面。 德尔福register
约定是私人德尔福,所以你应该使用stdcall
。
其次,你的字符串参数类型不匹配。 德尔福shortstring
是成为遗留在Delphi 2中被释放,并应被视为从上个世纪遗留下来的数据类型。 这是从来没有一个有效的互操作类型,并没有什么在P / Invoke的框架,可以用来匹配它。 虽然你可以尝试做手工编组,这是很多,当有可用简单的解决方案是根本没有必要的工作。 你应该试着去忘记所有关于shortstring
。
你需要使用一个字符串类型的接口的两侧可以工作。 你可以使用空值终止的C字符串,而是一个更好更简单的选择是COM BSTR
这是WideString
德尔福。
所以,最终的结果如下。
德尔福
function SMap4Ovr(
OverFileName: WideString;
Aclay: Integer;
Acarbon: Double;
out errstr: WideString
): WordBool; stdcall;
C#
[DllImport("SMap.dll")]
public static extern bool SMap4Ovr(
[MarshalAs(UnmanagedType.BStr)]
string OverFileName,
int Aclay,
double Acarbon,
[MarshalAs(UnmanagedType.BStr)]
out string errstr
);
我没有理会指定的调用约定DllImport
因为默认是stdcall
。 如果你愿意,你可以明确这一点。
使用时要小心WideString
,你不要试图使用它作为返回值 。 由于Delphi使用非标准的语义返回值,你只能使用简单的类型放入一个寄存器作为返回值。
在Delphi中默认调用约定注册,不STDCALL。 这似乎调用约定细节告诉我们,微软FASTCALL是不一样的FASTCALL Borland公司(注册)
和C#字符串类型距离Delphi ShortString短不同(它在内部包含一个字节长度+串体)