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

发布于 2025-01-06 06:14:12 字数 763 浏览 0 评论 0原文

如果我不返回任何内容,或者返回一个整数,则工作正常。但是,如果我尝试返回 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

轮廓§ 2025-01-13 06:14:12

Dampsquid 的分析是正确的,所以我不会重复。然而,我更喜欢不同的解决方案,我觉得更优雅。对于此类问题,我的首选解决方案是使用 Delphi Widestring,它是一个 BSTR

在 Delphi 方面,您可以这样写:

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

在 C# 方面,您可以这样写:

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

就是这样。因为双方使用相同的 COM 分配器进行内存分配,所以一切正常。

更新 1

@NoPyGod 有趣地指出,此代码因运行时错误而失败。经过研究后,我觉得这是 Delphi 端的问题。例如,如果我们保留 C# 代码不变并使用以下代码,则错误将得到解决:

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

看来 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 a BSTR.

On the Delphi side you write it like this:

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

And on the C# side you do it like this:

[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.

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:

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. 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 use WideString as a return type, instead return it via an out parameter. For more details see Why can a WideString not be used as a function return value for interop?

渔村楼浪 2025-01-13 06:14:12

您不能返回这样的字符串,该字符串是函数的本地字符串,一旦函数返回,该字符串就会被释放,使返回的 PChar 指向无效位置。

您需要传入一个要在 DLL 中填充的指针,动态创建字符串并将其释放回 C# 代码中,或者在您的 DLL 中创建一个静态缓冲区并返回它。

到目前为止,最安全的方法是将指针传递给函数,即

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

在调用 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

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.

蓝戈者 2025-01-13 06:14:12

尝试在应用程序池高级设置中启用 32 位应用程序:

在此处输入图像描述

try to enable 32-bit applications in application pool advanced settings :

enter image description here

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文