简体   繁体   English

在IIS网络服务器上调用Delphi DLL的ASP.NET Web应用程序,在返回PChar字符串时锁定

[英]ASP.NET web app calling Delphi DLL on IIS webserver, locks up when returning PChar string

Works fine if I don't return anything, or I return an integer. 如果我不返回任何内容,则工作正常,或者返回一个整数。 But if I try to return a PChar, ie.. 但如果我试图返回一个PChar,即...

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. 奇怪的是,DLL在VStudio调试服务器或C#应用程序上运行良好。 The only thing I can think of that would make a difference is that the IIS server is running in 64bit Windows. 我唯一能想到的就是IIS服务器在64位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. 它似乎不是一个兼容性问题,因为我可以成功写入文本文件并从DLL中执行其他操作...我只是不能返回一个PChar字符串。

Tried using PWideChar, tried returning 'something\\0', tried everything I could think of. 尝试使用PWideChar,尝试返回'something \\ 0',尝试了我能想到的一切。 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

Dampsquid's analysis is correct so I will not repeat that. Dampsquid的分析是正确的,所以我不再重复。 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 a BSTR . 我对这种问题的首选解决方案是使用Delphi Widestring ,这是一个BSTR

On the Delphi side you write it like this: 在Delphi方面,你这样写:

function SomeFunction: Widestring; stdcall;
begin
  Result := 'Hello';
end;

And on the C# side you do it like this: 在C#方面,你这样做:

[DllImport(@"TheLib.dll")]
[return: MarshalAs(UnmanagedType.BStr)]
private static extern string SomeFunction();

And that's it. 就是这样。 Because both parties use the same COM allocator for the memory allocation, it all just works. 因为双方都使用相同的COM分配器进行内存分配,所以这一切都正常。

Update 1 更新1

@NoPyGod interestingly points out that this code fails with a runtime error. @NoPyGod有趣地指出此代码因运行时错误而失败。 Having looked into this I feel it to be a problem at the Delphi end. 看了这个后,我觉得这是Delphi端的一个问题。 For example, if we leave the C# code as it is and use the following, then the errors are resolved: 例如,如果我们按原样保留C#代码并使用以下内容,则会解决错误:

function SomeFunction: PChar; stdcall;
begin
  Result := SysAllocString(WideString('Hello'));
end;

It would seem that Delphi return values of type WideString are not handled as they should be. 看起来Delphi类型WideString返回值没有得到应有的处理。 Out parameters and var parameters are handled as would be expected. Out参数和var参数按预期处理。 I don't know why return values fail in this way. 我不知道为什么返回值会以这种方式失败。

Update 2 更新2

It turns out that the Delphi ABI for WideString return values is not compatible with Microsoft tools. 事实证明,用于WideString返回值的Delphi ABI与Microsoft工具不兼容。 You should not use WideString as a return type, instead return it via an out parameter. 您不应该使用WideString作为返回类型,而是通过out参数返回它。 For more details see Why can a WideString not be used as a function return value for interop? 有关更多详细信息,请参阅为什么不能将WideString用作互操作的函数返回值?

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. 你不能返回这样的字符串,字符串是函数的本地字符串,一旦函数返回就会被释放,而返回的PChar指向无效的位置。

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. 你需要传入一个指针来填充DLL,动态创建字符串并将其释放回c#代码或在你的DLL中创建一个静态缓冲区并返回它。

By far the safest way is to pass a pointer into the function ie 到目前为止,最安全的方法是将指针传递给函数,即

function SomeFunction( Buffer: PChar; MaxLength: PInteger ): wordbool; stdcall;
{
  // fill in the buffer and set MaxLength to length of data
}

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. 你应该在调用dll之前将MaxLength设置为缓冲区的sixe,以便dll可以检查是否有足够的空间来返回数据。

try to enable 32-bit applications in application pool advanced settings : 尝试在应用程序池高级设置中启用32位应用程序:

在此输入图像描述

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM