【发布时间】:2015-10-21 06:18:52
【问题描述】:
我使用 C# DLL 导出 (UnmanagedExports - https://www.nuget.org/packages/UnmanagedExports) 使我的托管 C# DLL 可以访问像 Delphi 这样的非托管代码。我的问题是只有第一个函数参数从 delphi 传输到 C# dll:
C# DLL 部分
[DllExport("SomeCall", CallingConvention.StdCall)]
public static String SomeCall([MarshalAs(UnmanagedType.LPWStr)] String data1, [MarshalAs(UnmanagedType.LPWStr)] String data2)
{
//Data1 is never filled with some string data.
String result = WorkWithData(data1);
//Data2 is filled with some string data.
result += WorkWithData(data2)
return result;
}
Delphi 部分(调用部分):
SomeCall: function(data1: PWideChar; data2: PWideChar;): String StdCall;
procedure DoSomeDLLWork(data1: PWideChar; data2: PWideChar);
var
dllCallResult: String;
begin
dllCallResult := SomeCall(data1,data2);
end
这种情况下的问题是只填充了data2。 data1 永远不会被填充。我已经尝试过 StdCall 和 Cdecl。
编辑:
以下事情有效(data1 和 data2 传输正确) - 返回值从字符串更改为布尔值:
C#(DLL 部分):
[DllExport("SomeCall", CallingConvention.StdCall)]
public static bool SomeCall([MarshalAs(UnmanagedType.LPWStr)] String data1, [MarshalAs(UnmanagedType.LPWStr)] String data2)
Delphi(调用者):
SomeCall: function(data1: PWideChar; data2: PWideChar;): boolean StdCall;
现在我必须考虑一个返回值或一个缓冲区来将结果字符串返回给 delphi。
编辑2:
我同意 David Heffernan 的使用 out 参数的建议:
德尔福:
SomeCall: procedure(data1: PWideChar; data2: PWideChar; var result: PWideChar)StdCall;
C#
[DllExport("SomeCall", CallingConvention.StdCall)]
public static bool SomeCall([MarshalAs(UnmanagedType.LPWStr)] String data1, [MarshalAs(UnmanagedType.LPWStr)] String data2, [MarshalAs(UnmanagedType.LPWStr)] out String result)
【问题讨论】:
-
字符串返回值有问题。删除它并使函数无效,或返回 int 错误代码,或 bool 成功标志。
-
我会试试看(最终data1会被传输)。但我需要一个字符串作为返回值。我应该选择也使用 PWideChar 作为返回值吗?
-
想想内存管理。被调用者如何分配内存?谁解除分配。被调用者必须要么导出释放器,要么从共享堆中分配。或者让调用者分配和被调用者填充。
-
FWIW,我很难相信你在问题中声称的内容。似乎更合理的是错误出在调用代码中。你没有显示。或者你没有显示真正的代码。该问题的原始版本显然不包含真实代码。我不知道你为什么不显示minimal reproducible example。
-
您应该传递一个字符串缓冲区来放置要返回的字符串,作为参数。为字符串分配空间的责任应该落在 Delphi 代码上,而不是在 .NET 代码上,但是返回一个字符串会使它成为 .NET 的责任,并且解除分配缓冲区的责任应该在栅栏的同一侧作为分配。传入一个缓冲区,用文本填充它。
标签: c# delphi dll delphi-xe2 dllexport