ASP.NET Web 应用程序在 IIS Web 服务器上调用 Delphi DLL,在返回 PChar 字符串时锁定
如果我不返回任何内容,或者返回一个整数,则工作正常。但是,如果我尝试返回 PChar,即......
result := PChar('') or result:= PChar('Hello')
网络应用程序就会冻结,我会看到它的内存计数在任务管理器中逐渐变得越来越高。
奇怪的是,DLL 在 VStudio 调试服务器上或通过 C# 应用程序运行良好。我能想到的唯一会有所不同的是 IIS 服务器在 64 位 Windows 中运行。
不过,这似乎不是兼容性问题,因为我可以成功写入文本文件并从 DLL 执行其他操作...我只是无法返回 PChar 字符串。
尝试使用 PWideChar,尝试返回“something\0”,尝试了我能想到的一切。不幸的是没有运气。
[DllImport("TheLib.dll", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Ansi)]
private static extern string SomeFunction();
string result = SomeFunction();
德尔福:
library TheLib;
function SomeFunction() : PChar export; stdcall;
begin
return PChar('');
end;
exports
SomeFunction
Works fine if I don't return anything, or I return an integer. But if I try to return a PChar, ie..
result := PChar('') or result:= PChar('Hello')
The web app just freezes up and I watch its memory count gradually get higher and higher in task manager.
The odd thing is that the DLL works fine on the VStudio debug server, or through a C# app. The only thing I can think of that would make a difference is that the IIS server is running in 64bit Windows.
It doesn't appear to be a compatability issue though because I can successfully write to text files and do other things from the DLL... I just can NOT return a PChar string.
Tried using PWideChar, tried returning 'something\0', tried everything I could think of. No luck unfortunately.
[DllImport("TheLib.dll", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Ansi)]
private static extern string SomeFunction();
string result = SomeFunction();
delphi:
library TheLib;
function SomeFunction() : PChar export; stdcall;
begin
return PChar('');
end;
exports
SomeFunction
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
Dampsquid 的分析是正确的,所以我不会重复。然而,我更喜欢不同的解决方案,我觉得更优雅。对于此类问题,我的首选解决方案是使用 Delphi
Widestring
,它是一个BSTR
。在 Delphi 方面,您可以这样写:
在 C# 方面,您可以这样写:
就是这样。因为双方使用相同的 COM 分配器进行内存分配,所以一切正常。
更新 1
@NoPyGod 有趣地指出,此代码因运行时错误而失败。经过研究后,我觉得这是 Delphi 端的问题。例如,如果我们保留 C# 代码不变并使用以下代码,则错误将得到解决:
看来 Delphi 返回类型
WideString
的值未按应有的方式处理。 Out 参数和 var 参数按预期进行处理。我不知道为什么返回值会以这种方式失败。更新 2
事实证明,
WideString
返回值的 Delphi ABI 与 Microsoft 工具不兼容。您不应使用WideString
作为返回类型,而应通过out
参数返回它。有关更多详细信息,请参阅为什么 WideString 不能用作互操作的函数返回值?Dampsquid's analysis is correct so I will not repeat that. However, I prefer a different solution that I feel to be more elegant. My preferred solution for such a problem is to use Delphi
Widestring
which is aBSTR
.On the Delphi side you write it like this:
And on the C# side you do it like this:
And that's it. Because both parties use the same COM allocator for the memory allocation, it all just works.
Update 1
@NoPyGod interestingly points out that this code fails with a runtime error. Having looked into this I feel it to be a problem at the Delphi end. For example, if we leave the C# code as it is and use the following, then the errors are resolved:
It would seem that Delphi return values of type
WideString
are not handled as they should be. Out parameters and var parameters are handled as would be expected. I don't know why return values fail in this way.Update 2
It turns out that the Delphi ABI for
WideString
return values is not compatible with Microsoft tools. You should not useWideString
as a return type, instead return it via anout
parameter. For more details see Why can a WideString not be used as a function return value for interop?您不能返回这样的字符串,该字符串是函数的本地字符串,一旦函数返回,该字符串就会被释放,使返回的 PChar 指向无效位置。
您需要传入一个要在 DLL 中填充的指针,动态创建字符串并将其释放回 C# 代码中,或者在您的 DLL 中创建一个静态缓冲区并返回它。
到目前为止,最安全的方法是将指针传递给函数,即
在调用 dll 之前,应将 MaxLength 设置为缓冲区的 6 倍,以便 dll 可以检查是否有足够的空间用于返回数据。
You cannot return a string like that, the string is local to the function and will be freed as soon as he function returns leaving the returned PChar pointing to an invalid location.
you need to pass in a pointer to be filled within the DLL, dynamically create the string and free it back in the c# code or create a static buffer in yout DLL and return that.
By far the safest way is to pass a pointer into the function ie
you should set MaxLength to the sixe of the buffer before calling your dll so that the dll can check there is enough space for the data to be returned.
尝试在应用程序池高级设置中启用 32 位应用程序:
try to enable 32-bit applications in application pool advanced settings :